注:这是本人笔试期间总结的一些java知识点,太简单的没写,太深奥的疏漏较多,主要是针对较难易错点的的一些探讨,错误之处还望留言斧正。
一、基本类型以及对应的包装类的各种转换、比较
1、各种规则
- 自动类型转换顺序: byte/char/short -> int -> long -> float -> double
- 布尔型不参与自动类型转换
2、char、short、byte两两之间运算,都会转换为int
- 一下代码做出验证
Object o = null;
short a = 3;
byte b = 2;
char c = 3;
o = a + b;
System.out.println(o.getClass().getName()); // java.lang.Integer
o = a + c;
System.out.println(o.getClass().getName()); // java.lang.Integer
o = b + c;
System.out.println(o.getClass().getName()); // java.lang.Integer
- 由于向上转型,下边的第5、6行编译时就会报错:cannot convert from int to byte,为什么第4行可以呢?因为b3、b4都是final修饰的,在编译之后,这句就成了b5 = 7(也可能是b5 = 3 + 4,暂时还没搞清楚到底是是这两个哪一个,但是这两种形式都不会报错),自然没有问题
byte b1 = 1, b2 = 2;
final byte b3 = 3, b4 = 4;
byte b5;
b5 = b3 + b4; // 正确
b5 = b3 + b5; // 编译错误
b5 = b1 + b2; // 编译错误
3、几种易错的赋值方法
- 包装Long类型赋值需要加L,基本long无所谓
- float的包装和基本类型都要加F
Long l = 1L;
long ll = 1;
Float f = 0.1F;
float ff = 0.1F;
4、包装类型的继承关系
二、访问控制符、修饰符
1、两个级别的访问控制符
- 类级别:控制其他类能否使用该类。有2中类型:public 和 package-private(不写的话默认为此类型)
- 成员级别:控制某一方法变量的访问,有4种类型: public , protected, package-private(默认default), private
2、类级别的 package-private
- 也就是类没有访问控制符,这时该类除了能在本类中使用外,还能被同一个包中的其他类使用,不包括子包
3、成员级别修饰符
该成员所在类 | 该成员所在包 | 其他包子类 | 任何地方 | |
private | Y | N | N | Y |
default | Y | Y | N | N |
protected | Y | Y | Y | N |
public | Y | Y | Y | Y |
4、继承与访问修饰符
- 父类方法为public,子类也必须为public
- 父类为protected,子类必须为protected或者public
- 父类中的private方法没有继承的说法,如下,这样编译都不会报错,但子类的eat()方法与父类的没有任何关系
class People{
private void eat() {}
}
class Stu extends People{
public void eat() {}
}
- 子类继承方法的访问修饰符小于父类的范围时,编译报错,如下是错误的
class People{
protected void eat() {}
}
class Stu extends People{
private void eat() {}
}
5、接口
- 接口的属性都是由public static final修饰
- 接口的方法都是由public abstract修饰
6、成员内部类
- 内部类可以有protected和private修饰符
- 内部类拥有它所在外部类所有元素的访问权限。
- 可以实现多重继承(内部类存在的最大理由之一)
- 可以避免修改接口而实现同一个类中两种同名方法的调用
7、局部内部类
- 不能加访问修饰符,因为它们不是类成员
8、静态内部类
- 加static修饰符修饰
三、多态
1、子类重写、重载父类方法
- 指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的
- 重载的方法返回值可以不同
class People {
public int age() {
return 0;
}
public int[] age(int i) {
return new int[] {1};
}
}
- 若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)
public class Main {
public static void main(String[] args) {
People p = new Stu();
p.eat();
p.sleep();
p.eat("apple"); // 编译错误
}
}
class People{
public void eat() {
System.out.println("People eat");
}
public void sleep() {
System.out.println("People sleep");
}
}
class Stu extends People{
// 重载
public void eat(String food) {
System.out.println("Stu eat " + food);
}
// 重写(覆盖)
public void sleep() {
System.out.println("Stu sleep");
}
}
2、一个经典的多态例题
- 这是一个非常经典的多态例子,A、B、C、D类的各种参数调用,代码如下
public class Main {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); // A---A
System.out.println(a1.show(c)); // A---A
System.out.println(a1.show(d)); // A---D
System.out.println(a2.show(b)); // B---A
System.out.println(a2.show(c)); // B---A
System.out.println(a2.show(d)); // A---D
System.out.println(b.show(b)); // B---B
System.out.println(b.show(c)); // B---B
System.out.println(b.show(d)); // A---D
}
}
class A {
public String show(D obj) {
return "A---D";
}
public String show(A obj) {
return "A---A";
}
}
class B extends A {
public String show(B obj) {
return "B---B";
}
public String show(A obj) {
return "B---A";
}
}
- 首先贴上别人对这个的解释,也是我作为参考的,建议先看一下再回来接着看:https://blog.csdn.net/thinkGhoster/article/details/2307001
- 继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)
- 当超类对象引用变量 引用子类对象时,被引用对象的类型 决定了调用谁的成员方法,而不是引用变量的类型决定,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
- 分析第四行:a2.show(b),a2是A类型的,所以去A中找方法show(B obj),发现没有,但是由于A类没有父类,所以不去父类中了,B的父类的A,接着去A类中找show(A obj)方法,发现有此方法,执行。
- 分析第五行:a2.show(c),a2是A类型的,所以去A中找方法show(C obj),发现没有,但是由于A类没有父类,所以不去父类中了,C的父类的B,接着去A类中找show(B obj)方法,发现有此方法,但是此时a2是父类A的变量引用子类B的真实对象,所以是否调用A中show(B obj)方法,需要看子类B中是否重写(覆盖)了此方法,于是是B类中找show(B obj)方法,果真有覆盖了父类的方法,执行。
- 分析第八行:b.show(c),b是B类型的,所以去B中找方法show(C obj),发现没有,于是去B的父类A去找show(C obj),发现也没有,因为C类的父类是B,接着去B类中找show(B obj),有此方法,执行。
- 分析第九行:b.show(d),b是B类型的,所以去B中找方法show(D obj),发现没有,于是去B的父类A去找show(D obj),发现有此方法,执行。
四、构造器
- 访问修饰符:可以有public、protected、default、private,不能有abstract、final、native、static、synchronized。
- 在对象创建的时候才调用。
- super和this:用super()调用父类的构造器,如果不写,默认也会加上,如果在父类中没有不带参数的构造器,子类的构造函数中有没有调用父类的构造器,编译就会报错。this()调用本类中的构造方法。super()和this()都要放在构造器的第一行。从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
- 构造代码块:对象构建是先于构造方法运行,可以抽取多个构造函数中的公共部分,减少代码量