Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

java 基础知识整合

Javase 基础

基础数据类型

四类八种

  1. 整型

    1. Byte
    2. int
    3. short
    4. long
  2. 浮点

    1. float
    2. double
  3. 布尔

    1. boolean
  4. 字符型

    1. char

取值范围

  1. 整型:byte $-2^7 \to 2^7 -1$(10000000 表示-128)
  2. 浮点型:符号位 + 阶码(指数)+尾数
  3. 字符:一个字符两个字节(unicode)

字符发展

$ASCII \to ISO8856-7(1字节) \to unicode(2字节) \to utf-8(可变长字符集,英文1字节,中文2)$

GBK GB2312 中国国标字符集

变量

在内存中开辟一片空间,可以存数据

1
//变量类型 变量名 = 具体值
作用
  1. 可以反复使用
  2. 对于引用类型来说,变量就是一个引用,指向内存的一块区域,我们想操作一个对象只需要使用它的引用即可

标识符命名规则

  1. 可以用_或$
  2. 可以是字母数字,数字不能开头
  3. 所有名字必须驼峰式命名
  4. 变量、方法首字母小写,类名首字母大写,静态常量全部大写多个单词用下划线分割
  5. 不能使用关键字
  6. 少用或不用拼英,如果使用就整体全用拼英

强制类型转换

整型和整型:整型种小转大自动转,大转小需要强转,因为可能会丢失精度

整型和浮点型:浮点型转整型需要强转,反之不需要,但以科学计数法表示可能会丢失精度

char和整型:相互转换都为自动转换。

任何short、byte、int、char无论是逻辑运算还是数学运算的结果都是int

运算符

逻辑运算符

双与 双或 异或
& | && || ^
  1. 与:全真为真
  2. 或:全假为假
  3. 非:非真就是假、非假就是真
  4. 异或:相同为真不同为假
  5. 双与:短路元素运算符,前为假直接返回假,后面的不计算
  6. 双或:短路元素运算符,前为真直接返回真,后面的不计算

算术运算符

$+ - \times \div % $

赋值运算符

  • =
  • ++:++在前,先+再赋值,++在后先赋值再+

  • +=
  • -=
位运算符
  • >>:有符号右移
  • <<:有符号左移
  • >>>:无符号右移

三目运算符

1
//条件?结果一:结果二;

控制语句

选择结构

  • if语句
1
2
3
4
5
if (/*条件*/){

} else {

}
  • switch
1
2
3
4
5
6
7
8
9
10
11
12
//i可以是 byte short int String enum
switch(i){
case 1:
System.out.printin();//操作
break;
case 2:
System.out.printin();
break;
default:
System.out.printin();
break;
}

循环结构

  • while
1
2
3
4
5
while (/*条件*/){

}

do {} while (/*条件*/)//无论如何都会执行一次
  • for
1
2
3
4
//不同for
for (int i = 0; i < 10; i++){

}

数组

定义

1
2
3
//类型 名字[] = new 类型[长度];
//类型 名字[] = (1,2,3);
//类型 名字[]; new 类型[](1,2,3,4);

特性

  1. 一旦创建,类型、长度都无法更改
  2. length代表她长度
  3. 下标从0开始,最后一个位length - 1
  4. 使用 名字[下标] 访问
  5. 越界抛出:ArrayIndexOutOfBoundsException

方法

1. 权限修饰符

作用域 当前类 同package 子孙类 其他package
public
protected ×
friendly(default) 同包子类可以 ×
private × × ×

2. 返回值类型

3. static

静态方法和属性是属于类对象的,使用时不需要new对象,直接使用类名.方法名()类名.属性

4. 名字

驼峰式,首字母小写

5. 参数

参数可以有多个,方法定义的地方叫形参,方法调用的地方叫实参

可变参数:

  1. 只能出现一次
  2. 必须放在最后
1
public void f1(int ... nums){}

方法重载

  1. 方法名一样
  2. 参数列表不一样
  3. 每个方法都有一个签名,就是用名字和参数签名的

递归

  1. 方法自己调用自己的过程
  2. 一定要有出口,没有出口将会栈内存溢出
  3. 斐波那契数列

6. 面向对象

封装

需要什么对象,就创建一个什么类,万物皆对象

1
2
3
4
5
6
7
8
9
10
public class User{
//使用public修饰时,文件名必须与类名相同
//一个文件中只能有一个被public修饰的类

//私有属性(属性推荐私有)
//构造器 (可有0-多个)
//实例方法
//getter and setter
//toString(如果需要)
}
工具类和常量类

工具类中一般多为静态方法,常量类中大多时静态常量

1
public static final String ORDER_SRARUS = "已发货";
属性

属性全部私有,使用getter取值,setter赋值,能做安全控制

方法
构造器
  1. new一个对象时会主动调用他的构造器
  2. 构造器可有多个
  3. 可以有不同参数的构造器
  4. 不自己写,就默认给一个无参构造器,一旦写了有参构造器,无参构造器就需要自己手写

继承

  1. extends关键字,子类拥有父类(超类)的一切(除了被private修饰的)
  2. 构造子类时一定会先构造一个父类
  3. 子类可以重写父类的方法,重写的方法需要加一个注释@override
  4. Object 时所有类的顶级父类
类的构造顺序
  1. 父类的静态属性
  2. 父类的静态代码块
  3. 子类的静态属性
  4. 子类的静态代码块
  5. 父类的非静态属性
  6. 父类的非静态代码块
  7. 父类的构造器
  8. 子类的非静态属性
  9. 子类的非静态代码块
  10. 子类的构造器
this&super
  1. this 指向本实列
  2. super指向父类的实例
  3. this和super可当构造器使用,但如果想使用super()必须放在第一行

多态

  1. 继承
  2. 重写
  3. 父类引用指向子类对象
1
2
List<Integer> list = new ArrayList();
List.add(1);
Object的几个方法
  1. equals
  2. hashcode
  3. 重写equals必须重写hashcode,主要是因为有hashmap,hashset这类的集合
  4. toString

抽象类和接口

抽象类:拥有抽象方法的类,必须使用abstract修饰,可以没有抽象方法,继承时必须重写她的抽象方法

接口:全部都是抽象方法的类(没有方法体的方法),interface

实现接口implements,必须实现所有的抽象方法

类型转换

  1. 父类引用 $\to$ 子类对象 不需要强转 向下转型
  2. 子类引用 $\to$ 父类的对象 需要强转 向上转型

集合

集合是存东西的,能存很多同一种类型(包含他的子类)的对象

collection

list(列表)

ArrayList

LinkList

set

set和list的区别:

list是有序(指插入顺序和实际位置相关)、可重复的

set是无序(hash算法来确定位置)、不可重复的

hashset如何判断一个对象是否重复:

如果两个对象不是用同一地址,但是equals且hashcode一样,就说明一样

map(映射)

存一对key与value的映射

hashmap原理:数据结构是:数组+链表+红黑树

hashmap是无序的

集合遍历方式

list:普通for,增强for,迭代器(iterator)

set:增强for,迭代器

set两种遍历方式

1
2
3
4
5
6
7
8
9
//增强for
for (Integer integer : set){
System.out.printlen(integer);
}
//迭代器
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()){
System.out.printlen(iterator.next());
}

hashmap:entryset,迭代器

hashmap三种遍历方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//第一种
for (Map.Entry entry : map.entrySet() ){
System.out.printlen(entry.getKey());
System.out.printlen(entry.getValue());
}
//第二种
Set<String> keys = map.keySet();
for (String key : keys){
System.out.printlen(key);
}
//第三种
Iterator<map.Entry, User> > iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, User> next = iterator.next();
System.out.printlen(next.getKey());
System.out.printlen(next.getValue());
}

TreeMap

自动排序的map,数据结构是红黑树

TreeSet:底层就是一个TreeMap

泛型

引用自

定义

什么是泛型,看表面的意思,泛型就是指广泛的、普通的类型。在java中是指把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型

例子:

1
2
3
List<String> strings = new ArrayList<String>();
strings.add("a String");
String aString = strings.get(0);

通过<>可以将List内元素的类型限定为String类型,其中只能是引用类型,对于基本类型,可以使用对应的包装类型

泛型类

泛型类也就是把泛型定义在类上,这样用户在使用类的时候才把类型给确定下来。

1
2
3
4
5
6
7
8
9
10
11
public class ObjectTool<T> {
private T obj;

public T getObj() {
return obj;
}

public void setObj(T obj) {
this.obj = obj;
}
}

可以看到上面这个程序,在使用时如果定义了类型,那么在使用时就可以不用进行强制类型转换,直接就可以得到一个T类型的对象。

泛型方法

有时候只关心某个方法,那么使用泛型时可以不定义泛型类,而是只定义一个泛型方法,如下

1
2
3
public <T> void show(T t) {
System.out.println(t);
}

需要注意一下定义的格式,泛型必须得先定义才能够使用。

继承关系

泛型类在继承时,可以明确父类(泛型类)的参数类型,也可以不明确。
现在我们有如下的泛型类
//泛型类

1
2
3
public interface Inter<T> {
public abstract void show(T t);
}
明确类型

//在实现泛型类时明确父类的类型

1
2
3
4
5
6
public class InterImpl implements Inter<String> {
@Override
public void show(String s) {
System.out.println(s);
}
}
不明确类型
1
2
3
4
5
6
7
public class InterImpl<T> implements Inter<T> {

@Override
public void show(T t) {
System.out.println(t);
}
}

类型通配符

无界

类型通配符我感觉上和泛型方法差不多,只是不用在使用前进行定义,例子如下:

1
2
3
4
5
public void processElements(List<?> elements){
for(Object o : elements){
System.out.println(o);
}
}

“?”可以接收任何类型。

上界
1
2
3
4
5
public void processElements(List<? extends A> elements){
for(A a : elements){
System.out.println(a.getValue());
}
}

这种情况下能够接收A类或者A类的子类。

下界
1
2
3
4
5
public static void insertElements(List<? super A> list){
list.add(new A());
list.add(new B());
list.add(new C());
}

这种情况下能够接收A类或者A类的父类

类型通配符和泛型方法

我认为这两种方式是差不多的,不过在使用时,如果参数之间是有依赖关系的,那么可以使用泛型方法,否则就使用类型通配符。(如果一个方法的返回值、某些参数的类型依赖另一个参数的类型就应该使用泛型方法,因为被依赖的类型如果是不确定的?,那么其他元素就无法依赖它)

泛型擦除

泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

多线程

  1. 继承Thread类,实现run方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyThread extends Thread {
public static void main(String[] args){
MyThread t1 = new MyThread("t1");
t1.start();
}
public MyThread(){}
public MyThread(String name){
super(name)
}

@override
public void run(){
while(true){
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("我是:" + Thread.currentThread().getName());
}
}

}
  1. 实现runnable接口,实现run方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyRun implements Runnable {
public static void main(String[] args){
Thread t1 = new Thread(new MyRun());
t1.start();
}

@override
public void run(){
for(int i = 0; i < 100; i++){
ThreadTest.SB.append(1);
}
}

}

启动线程必须调用start方法,不能调用run,调用run只是方法调用,start是个native的本地方法,会调度cpu的资源,开辟线程

常用类

String

String是引用数据类型,是final修饰的,一旦创建无法改变

String、StringBuffer、StringBuilder的区别

  1. String不可变,线程安全的
  2. StringBuffer是可变字符串,线程安全的
  3. StringBuilder是可变字符串,前程不安全
  4. 当有大量字符串拼接的代码时,没有线程安全的要求就用StringBuilder(一般情况),有要求就用StringBuffer

工具类

Date、Math、Collections、Arrys、Canlader

Date格式化:

1
2
3
Date date = new Date();
SimpleDateFormate s = new SimpleDateFormate("yyyy-MM-dd hh:mm:ss");
String DateString = s.parse(date);

枚举

引用自

什么是枚举?

我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
我们称呼枚举类中实例为枚举项!一般一个枚举类的枚举项的个数不应该太多,如果一个枚举类有30个枚举项就太多了!

定义枚举类型

定义枚举类型需要使用enum关键字,例如:

1
2
3
4
public enum Direction {
FRONT, BEHIND, LEFT, RIGHT;
}
Direction d = Direction.FRONT;

枚举可以用equals以及==来比较

枚举与switch

枚举类型可以在switch中使用

1
2
3
4
5
6
7
8
9
10
Direction d = Direction.FRONT;
switch(d) {
case FRONT: System.out.println("前面");break;
case BEHIND:System.out.println("后面");break;
case LEFT: System.out.println("左面");break;
case RIGHT: System.out.println("右面");break;
default:System.out.println("错误的方向");
}
Direction d1 = d;
System.out.println(d1);

在switch中,不能使用枚举类名称,例如:“case Direction.FRONT:”这是错误的,因为编译器会根据switch中d的类型来判定每个枚举类型,在case中必须直接给出与d相同类型的枚举选项,而不能再有类型。

Enum类及方法

所有枚举类都是Enum的子类
所有枚举类都默认是Enum类的子类,无需我们使用extends来继承。这说明Enum中的方法所有枚举类都拥有。

  • int compareTo(E e):比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序,例如FRONT的下标为0,BEHIND下标为1,那么FRONT小于BEHIND;
  • boolean equals(Object o):比较两个枚举常量是否相等;
  • int hashCode():返回枚举常量的hashCode;
  • String name():返回枚举常量的名字;
  • int ordinal():返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0;
  • String toString():把枚举常量转换成字符串;
  • static T valueOf(Class enumType, String name):把字符串转换成枚举常量。

枚举类构造器

枚举类也可以有构造器,构造器默认都是private修饰,而且只能是private。因为枚举类的实例不能让外界来创建!

1
2
3
4
5
6
7
enum Direction {
FRONT, BEHIND, LEFT, RIGHT;//[在枚举常量后面必须添加分号,因为在枚举常量后面还有其他成员时,分号是必须的。枚举常量必须在枚举类中所有成员的上方声明。]

Direction()//[枚举类的构造器不可以添加访问修饰符,枚举类的构造器默认是private的。但你自己不能添加private来修饰构造器。] {
System.out.println("hello");
}
}

其实创建枚举项就等同于调用本类的无参构造器,所以FRONT、BEHIND、LEFT、RIGHT四个枚举项等同于调用了四次无参构造器,所以你会看到四个hello输出。

枚举类成员

其实枚举类和正常的类一样,可以有实例变量,实例方法,静态方法等等,只不过它的实例个数是有限的,不能再创建实例而已。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Direction {
FRONT("front"), BEHIND("behind"), LEFT("left"), RIGHT("right");

private String name;

Direction(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
Direction d = Direction.FRONT;
System.out.println(d.getName());

因为Direction类只有唯一的构造器,并且是有参的构造器,所以在创建枚举项时,必须为构造器赋值:FRONT(“front”),其中”front”就是传递给构造器的参数。你不要鄙视这种语法,你应该做的是接受这种语法!
Direction类中还有一个实例域:String name,我们在构造器中为其赋值,而且本类还提供了getName()这个实例方法,它会返回name的值。

枚举类抽象方法

还可以在枚举类中给出抽象方法,然后在创建每个枚举项时使用“特殊”的语法来重复抽象方法。所谓“特殊”语法就是匿名内部类!也就是说每个枚举项都是一个匿名类的子类对象!

通常fun()方法应该定义为抽象的方法,因为每个枚举常量都会去重写它。
你无法把Direction声明为抽象类,但需要声明fun()方法为抽象方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum Direction {
FRONT() {
public void fun() {
System.out.println("FROND:重写了fun()方法");
}
},
BEHIND() {
public void fun() {
System.out.println("BEHIND:重写了fun()方法");
}
},
LEFT() {
public void fun() {
System.out.println("LEFT:重写了fun()方法");
}
},
RIGHT() {
public void fun() {
System.out.println("RIGHT:重写了fun()方法");
}
};

public abstract void fun()[只需要把fun()方法修改为抽象方法,但不可以把Direction类声明为抽象类。];
}

每个枚举类两个特殊方法

每个枚举类都有两个不用声明就可以调用的static方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方,下面是Direction类的特殊方法。

  • static Direction[] values():返回本类所有枚举常量;
  • static Direction valueOf(String name):通过枚举常量的名字返回Direction常量,注意,这个方法与Enum类中的valueOf()方法的参数个数不同。

分类

  1. 字节流
  2. 字符流
  3. 输入流
  4. 输出流

按输入输出分:输入流、输出流

按字符字节分:字符流、字节流

按直接使用还是增强分:节点流和处理流:

关键字

input输入

output输出

stream流

writer字符输入流

reader字符输入流

File文件

异常

checked 检测性异常

再编译时就使用try、catch来预先捕获、提供解决方案

FileNotFoundException IOException InterruptedException

继承自Exception,必须捕获并处理

运行时异常

自己的原因,通过检查一下解决

ArryIndexOutOfBoundsException ClassCastException 数学类异常(除0)

这种异常继承RuntimeException,不需要捕获,需要通过检查来预防

错误 error

StackOutOfMemoryError:如递归出不去

自定义异常

有时需要通过自定义异常来帮助处理一些业务

评论