··
一. 继承
1.1 何为继承?
简单来说:就是对共性的抽取,从而达到代码的复用
class Animal{
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String name;
public int age;
public void eat(){
System.out.println(name+"正在吃饭!");
}
}
class Dog extends Animal{ //Dog 就是子类 继承了 父类的 Animal
public Dog(String name,int age) {
super(name, age);
}
public void bark(){
System.out.println(name+"汪汪叫!");
}
}
class Cat extends Animal{
public Cat(String name,int age) {
super(name,age);
}
public void catchMouse(){
System.out.println(name+"正在抓老鼠!");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog("旺财",5);
Cat cat = new Cat("咪咪",6);
dog.bark();
cat.catchMouse();
}
}
Dog 与 Cat 类 都有共同的属性:name,age 所以我们建立一个父类 Animal 将共有的属性抽出来,减少了代码长度
简而言之就是将:相同属性抽出来
子类叫 派生类
父类叫 基类 也叫超类
当子类 继承 父类 会把属性 和 方法 全部继承!
1.2 父类成员访问
①. 当父类与子类都拥有 同名的变量时,优先访问子类自己!
②.方法也是如此,若名称完全相同,有时候需要看参数配对!
但如果子类和父类同名时非要访问 父类时我们要怎么做呢?
加super!
class A{
public int a=0;
public int b=0;
public int c=0;
}
class B extends A{
int a;
int b;
int c;
public void method(){
super.a = 10; //当父类和子类拥有相同的 (同名的)变量时,优先访问子类自己
b = 20;
c = 30;
System.out.println(super.a); 10
System.out.println(a); 0
System.out.println(super.b); 0
}
}
1. 每一个类 都会生成自己的字节码文件! 不能多继承(接口解决)
①.this 会优先访问 子类自己,如果 子类没有,访问的是父类的
②.super 只是一个关键字,在代码层面,仅仅只是达到易读效果!!!
super不是父类的引用!
1.3 super
super的作用就是 在子类方法中访问父类的成员
super的三种用法
1. super.data; 调用父类的普通成员变量
2.super.func(); 调用父类的普通成员方法
3.super(); 调用父类的构造访问
要注意的是:
super只能在非静态的情况下使用
因为在静态的情况下不依赖对象所以不能使用 this super
1.4 子类的构造
先给父类构造 super必须第一行
class Animal{
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String name;
public int age;
public void eat(){
System.out.println(name+"正在吃饭!");
}
}
class Dog extends Animal{ //Dog 就是子类 继承了 父类的 Animal
pubilc boolean silly;
public Dog(String name,int age) {
super(name, age);
//1.先帮父类初始化
this.silly = ture;
}
public void bark(){
System.out.println(name+"汪汪叫!");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog("旺财",5);
dog.bark();
}
}
注意:
1.若没有父类显式定义无参或默认的构造方法,在子类构造方法第一行默认有隐含的super()调用。即调用基类构造方法
2.如果父类构造方法是带有参数的,需要子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用!
3.在子类构造方法中,super调用父类构造方法中必须 是子类构造方法中的第一条语句!
4.super不能和this同yo时出现,super只能出现一次
1.5 super和this
不同点:
1.this 是对当前对象的引用,当前对象即调用实例方法的对象,super相当于子类对象中从父类继承下来的成员的引用!//引用对象不同
2.this 是访问本类的方法与属性,super是访问父类继承下来的方法与属性
3.在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法
二者不能同时存在!
//访问对象不同
4. 构造方法一定存在super(..)的调用,this(..)用户不写,就没有!
class Animal{
static {
System.out.println("Animal::static"); //①
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Animal(String name, int age)"); //②
}
{
System.out.println("Animal::{}"); //③
}
public String name;
public int age;
public void eat(){
System.out.println(name+"正在吃饭!");
}
}
class Dog extends Animal{
static {
System.out.println("Dog::static"); //④
}
public String name;
public int age;
public Dog(String name,int age) {
super(name, age);
System.out.println("Dog(String name,int age)"); //⑤
}
{
System.out.println("Dog::{}"); //⑥
}
public void bark(){
System.out.println(name+"汪汪叫!");
}
}
六个sout顺序是如何呢?
1-4-3-6-2-5
顺序是:静态先执行 在分别执行实例代码块+构造!
1.6 protected
不同包的子类--同一包的不同类:在另一个包也可以访问!
1.7final修饰
①.修饰变量和字段,表示常量(不能修改)
final int a = 10;
a = 20;//error
②.修饰类:表示此类不能被继承
final public class Animal{
...
}
public class Bird extends Animal{
...
} //error
③.修饰方法
二.多态:同一事件发生在不同对象身上,结果确实不一样,这种思想叫多态
对象不一样,行为就可能不一样!!
2.2 多态实现条件:
1.必须在继承体系中
2.子类对父类重写
简简单单举个例子:
//Animal
pubilc void eat(){
System.out.println(name+"吃饭!");
}
//Dog
public void eat(){
System.out.println(name+"正在吃狗粮!");
}
Dog类中就实现了对eat的重写:
1.方法名称相同,返回值相同
2.参数列表相同
注意的是 这俩个类 可以不用public修饰,但要遵守的规则是:
子类的访问权限 >= 父类的访问权限所以子类要么写public 要么不写
以下不可以重写:
1.private修饰的方法不可用于重写
2.final为 密封方法 不可重写
3.被static修饰的方法 不可以重写!
2.3 重写
定义:也叫覆盖。重写的是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重写编写,返回值和形参都不能改变。即外壳不变,核心重写!其好处在于 子类可以根据需要,定义特定于自己的行为。也就是子类能根据需要实现父类的方法!
规则:
1.子类在重写的过程中,一般必须与父类方法原型相同:返回值 方法名 参数列表 要相同!
2.返回值也可以不同,但必须构成父子关系!
3.父类被static,private修饰的方法,构造方法都不能被重写!
4.需要override注解
这里可以延申一个面试的小问题:
重写与重载的区别
也就是在参数列表,返回值不一样
重载的参数列表不同,返回值不做要求
重写的参数列表相同,返回值相同,构成父子关系也可以
静态绑定
编译的时候 根据你传入的数据 来确定你调用哪个方法,这种就叫静态绑定!
2.4 向上转型/向下转型
2.4.1 向下转型 子类对象对父类
public static void main(String[] args){
Dog dog = new Dog();
//animal这个引用指向了dog对象
Animal animal = dog;
//animal 没有的属性不能访问!
animal.eat():
}
eat方法 animal和dog类都有 所以可以访问
因此:向上转型只调用自己特有的属性和重写
这里eat方法的调用要注意的是:编译的时候 调用的还是Animal的eat,但程序运行的时候,变成了子类的eat,这就是动态绑定!
介绍一下写法:
1.直接赋值
Animal animal2 = new Dog();
Animal animal3 = new Cat();
2.利用参数接收
3.利用方法的返回
在main直接调用就行!
2.4.2 向下转型
尽量不要使用,非常危险