一、隐藏
重写是子类覆盖父类的对象方法;
隐藏是子类覆盖父类的类方法;
在Hero类中设计静态方法(类方法)battleWin()
public static void battleWin(){
System.out.println("Hero battle win");
}
并在子类(ADHero)中隐写:
public static void battleWin(){
System.out.println("ADHero battle win");
}
public static void main(String[] args){
Hero.battleWin();//静态类方法,可以直接通过类调用
ADHero.battleWin();//静态方法(类方法),通过类调用无需实例化
//问题:
Hero h = new Hero();
h.battleWin();//调用的是父类的方法,还是子类的方法?
}
输出:
Hero battle win
ADHero battle win
Hero battle win
结果显示,虽然h指向的是对象ADHero,但h的类型为Hero,所以调用的是父类的方法。
并且此时eclipse还会警告提示,要么将改引用的对象、要么改类方法为静态方法。
二、super关键字
讲道理有点懵
1 实例化子类的方法时,父类的构造方法一定会被调用
2 子类使用关键字super显示的调用父类带参的构造方法
作为子类,无论如何都会调用父类的构造方法。默认调用父类的无参的构造方法。但是,当父类没有无参构造方法的时候( 提供了有参构造方法,并且不显示提供无参构造方法),子类就会抛出异常,因为它尝试去调用父类的无参构造方法。这个时候,必须通过super去调用父类声明的、存在的、有参的构造方法。
public ADHero(String name,float hp){
super(name,hp); //直接调用了父类的构造方法
System.out.println("ADHero 的有参构造方法(super)");
}
2.调用父类属性
通过super调用父类的moveSpeed属性,以及调用
ADHero提供的属性moveSpeed;
public int getMoveSpeed(){
return this.moveSpeed;//子类的移动方法,设为400
}
public int getMoveSpeed2(){
return super.moveSpeed;//父类的移动方法为定义,默认为0
}
运行代码块结果如下:
System.out.println(delaiwen.getMoveSpeed()); //400 ,子类的定义的400
System.out.println(delaiwen.getMoveSpeed2());//0,父类默认的速度
2.调用父类方法
这里懵了,先不管
三、Object类
Object类是所有类的父类,声明一个类时,默认继承了Object;
1. toString
Object类提供一个toString方法,所以所有的类都有toString方法,toString()的意思是返回当前对象的字符串表达通过 System.out.println 打印对象就是打印该对象的toString()返回值。
System.out.println(h,toString());//h@139a55
System.out.println(h);//结果是一样的
2. finalize()
当一个对象没有任何引用指向的时候,它就满足垃圾回收的条件.当它被垃圾回收的时候,它的finalize() 方法就会被调用。finalize() 不是开发人员主动调用的方法,而是由虚拟机JVM调用的。
public void finalize(){
System.out.println("这个英雄正在被回收");
}
结果:
...
这个英雄正在被回收
这个英雄正在被回收
这个英雄正在被回收
这个英雄正在被回收
这个英雄正在被回收
这个英雄正在被回收
3. equals()
equals() 用于判断两个对象的内容是否相同,
/*instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。
instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
*/
public boolean equals(Object o){//传参为类 o
if(o instanceof Hero){//如果o是Hero的子类
Hero h = (Hero) o;//强制转换,子类转父类
return this.hp == h.hp;
}
return false;
4. ==
用于判断两个引用,是否指向了同一个对象
System.out.println(h1==h2);
5. hashCode()
hashCode方法返回一个对象的哈希值
6. 线程同步
7. getClass()
四、final
final修饰类,方法,基本类型变量,引用的时候分别有不同的意思。
1. final修饰类
当Hero被修饰成final的时候,表示Hero不能够被继承,其子类会出现编译错误。
public final class Hero{
}
2. final修饰方法
如果一个方法被修饰成final,那么该方法在子类中不能够被重写。
public final void useItem(Item i){
...
}
3. final修饰基本变量
final修饰基本类型变量,表示该变量只有一次赋值机会 。
final int hp;
4. final修饰引用
final修饰引用,h引用被修饰成final,表示该引用只有1次指向对象的机会。
final Hero h;
5. 常量
常量指的是可以公开,直接访问,不会变化的值
比如 itemTotalNumber 物品栏的数量是6个
public static final int itemTotalNumber = 6;//物品栏的数量
五、抽象类
1. 抽象方法
在类中声明一个方法,这个方法没有实现体,是一个“空”方法 。这样的方法就叫抽象方法,使用修饰符“abstract" 。当一个类有抽象方法的时候,该类必须被声明为抽象类。
当为Hero增加一个abstract方法attack,并把Hero声明为abstract。(抽象类可以没有抽象方法)
package charactor;
public abstract class Hero{
String name;
float hp;
float armor;
int moveSpeed;
public abstract void attack();
public static void main(String[] arg){
}
}
在Hero类中增加了abstract抽象方法attack,在子类中必须实现该方法。
public void attack() {
// TODO Auto-generated method stub
}
当一个类被声明为抽象类时就不能够被实例化。
2. 抽象类和接口的区别
区别1:
- 子类只能继承一个抽象类,不能继承多个
- 子类可以实现多个接口
区别2:
- 抽象类可以定义
public,protected,package,private
静态和非静态属性
final和非final属性 - 接口中声明的属性
只能是
public
静态
final的
六、内部类
1. 非静态内部类
非静态内部类可以直接在一个类里面定义,
实例化的时候,必须建立在一个存在的类的基础
语法: new 外部类().new 内部类()
2. 静态内部类
非静态内部类不同,静态内部类的实例化 不需要一个外部类的实例为基础,可以直接实例化
语法:new 外部类.静态内部类();
3. 匿名类
直接实例化一个抽象类,并“当场”实现其抽象方法。既然实现了抽象方法,那么就是一个新的类,只是这个类,没有命名。这样的类,叫做匿名类
4.本地类
本地类可以理解为有名字的匿名类。
内部类与匿名类不一样的是,内部类必须声明在成员的位置,即与属性和方法平等的位置。本地类和匿名类一样,直接声明在代码块里面,可以是主方法,for循环里等等地方。
创建一个Item的匿名类,Item有抽象方法disposable(),
package property;
public abstract class Item {
public String name;
int price;
public abstract boolean disposable();
public static void main(String[] args){
Item ig = new Item(){
public boolean disposable(){
return false;
}
};
System.out.println(ig);
System.out.println(ig.disposable());
}
}
结果:
property.Item$1@1db9742
false
七、默认方法
默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法。
Mortal 这个接口,增加了一个默认方法 revive,这个方法有实现体,并且被声明为了default。
package charactor;
public interface Mortal {
public void die();
default public void revive(){
System.out.println("本英雄复活了");
}
}
假设没有默认方法这种机制,那么如果要为Mortal增加一个新的方法revive,那么所有实现了Mortal接口的类,都需要做改动。
但是引入了默认方法后,原来的类,不需要做任何改动,并且还能得到这个默认方法
通过这种手段,就能够很好的扩展新的类,并且做到不影响原来的类
如果某个类同时实现了两个接口,且都有同样的默认方法,那么该类的实例化对象调用接口中的该默认方法时,必须重写该方法。不然会混淆到底实现的是哪个接口的方法?