重写和重载
重写
- 发生在父子类之间
- 参数列表必须完全与被重写的方法相同
- 返回值类型与被重写的方法可以部相同,但是必须与父类返回值派生类相同
- 访问权限不能比父类中被重写的方法的访问权限低(如果父类为public,重写的方法不能为protected)
- 父类的成员方法只能被它的子类重写
- 声明为final的类不能被重新
- 声明为static的类不能被重写,但是可以被再次声明
- 子类和父类在同一个包中,子类可以重写父类所有的方法,除了什么为private和final的方法;
- 子类和父类不在同一个包中,那么子类只能重写父类声明为public和protected的非final方法
- 重新的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是重写的方法不能抛出新的强制性异常,反之则可以
- 构造方法不能被重写
- 如果不能继承一个方法,则不能重写这个方法
- 总结:重写受约束、重写权限要高、重写异常要低
- 子类覆写父类方法或者实现接口时,必须加上 @Override注解
重载
- 是在一个类中
- 方法名相同,参数不同,返回值可同可不同,修饰符可同可不同
- 每个重载方法都必须有个独一无二的参数类型列表
- 最常用的重载是 构造器的重载
- 被重载的方法可以声明新的或者更广的检查异常
- 应该避免基本类型和其包装类型的同名重载,建议不重载
避免隐藏(hide),避免遮蔽(shadow),避免遮掩(obscure)
避免在无关的变量或者无关的概念之间重用名字
隐藏(hide)
- 丰富子类与父类之间
- 一个类的属性、静态方法或者内部类客运分别隐藏 在其超类中可访问到的具有相同名字的所有属性、静态方法和内部类,上述成员被隐藏后,将阻止其被继承:
// 定义 子类和父类
class Swan {
protected String name = "Swan";
public static void fly() {
System.out.println("swan can fly");
}
}
class uglyDuck extends Swan {
protected String name = "uglyDuck";
public static void fly() {
System.out.println("ugly duck can't fly");
}
}
// 调用
public static void main(String[] args) {
Swan swan = new Swan();
Swan uglyDuck = new uglyDuck();
swan.fly(); // swan can fly
uglyDuck.fly(); // swan can fly 方法名称相同,隐藏了,还是用的父类的
System.out.println(swan.name); // Swan
System.out.println(uglyDuck.name); // Swan 变量名称相同,隐藏了,还是用的父类的
}
遮蔽(shadow)
- 类内部
- 一个变量、方法或者类可以分别遮蔽在类内部具有相同名字的变量、方法或者类。
- 一个实体被遮蔽了,那么就无法用简单名引用到它。
static String sentence = "I don't know.";
public static void main(String[] args) {
String sentence = "I know.";
System.out.println(sentence);
// 方法的局部变量遮蔽了类大静态变量,反例
}
遮掩(obscure)
- 类内部
- 一个变量可以遮掩机油相同名字的另一个类,只要在同一个范围内:如果这个名字被引用于变量和类都许可的范围,那么将引用到变量上。即一个变量可以遮掩一个包/类。
- 遮掩事唯一 两个名字在不同命名空间的名字重用形式,空间包括 :变量、包、方法或者类型。
- 如果一个类/包被遮掩了,那么不能通过简单名引用到它
- 遵守命名规范,可以极大消除遮掩的可能性
- 如下反例:System应用到了static的属性,导致原System失效
类加载顺序
- 父类静态变量显示赋值、父类静态代码块(按定义顺序)
- 子类静态变量显示赋值、子类静态代码块(按定义顺序)
- 父类非静态变量显式赋值(父类实例成员变量)、父类非静态代码块(按定义顺序)
- 父类构造函数
- 子类非静态变量(子类实例成员变量)、子类非静态代码块(按定义顺序)
- 子类构造函数
Interface默认的修饰符
Java中Interface方法默认访问修饰符为:public abstract
Java中Interface常量的默认访问修饰符为:public static final
Final类型变量初始化
- 没有static修饰:只能在定义处、初始化、构造函数三处选一处进行初始化,初始化后,无法改变
- 有static修饰:只能在定义处、静态代码初始化二处选一处进行初始化,初始化后无法改变
- 声明为final的局部变量必须且只能在使用前初始化一次,不使用的话可以不进行初始化
类加载器,在Java虚拟机角度看,只有两种:
- 启动类加载器:使用C++实现(仅限于Hotspot,也就是JDK1.5之后默认的虚拟机,有很多其他的虚拟机是用Java实现的),是虚拟机自身的一部分
- 所有其他的类加载器:这些类加载器都是有Java实现的,独立于虚拟机之外,并且全部继承自抽象类java.lang.ClassLoader,这些类加载器需要由启动类加载器加载到内存中之后才能去加载其他的类
instanceof 可以和父类进行比较吗?
instanceof 作用是 测试左边对象是否是它右边的类的实例,返回boolean类型结果
- 子类对象 instanceof 父类 对
- 子类.class == 父类对象getClass 对
getClass() 时一个对象实例的方法只有对实例才有这个方法,具体类没有
类的class实例时通过.class 获取的
若父类的构造函数有参数,则子类构造函数中需要显示调用该父类构造函数
不显示调用会编译错误
正确写法
开发者是否可以自定义类加载器
可以自定义类加载器,同一个类使用不同的类加载器,会在方法区产生两个不同的类,彼此不可见,并且在堆中生产不同class实例
由不同的类加载器指定的类型是否想通?
不相同
java动态代理(类型RPC框架)问什么阶段是生效的?
运行阶段
定义本地方法
- public native void XXX();
- native 是关键字,注意项:
- native与访问控制符前后的关系不受限制
- 必须在返回类型之前
- 一般为抽象方法
- nvtice方法在异步实现,和抽象类一样,所有没有具体方法体,分号结束
类加载器顺序
Bootstrap Classloder-> Extention ClassLoader -> AppClassLoader
接口缺省值
- 属性缺省值:public static final
- 方法缺省值:public abstract