分卷写吧,感觉有点长
继承
继承主要解决的问题是:共性的抽取,实现代码复用。
public class Cat {
public String name;
public int age ;
public void eat() {
System.out.println (this.name + "正在吃饭");
}
public void mimi(){
System.out.println (this.name + "正在叫");
}
}
public class Dog {
public String name;
public int age ;
public void eat(){
System.out.println (this.name + "正在吃饭");
}
public void beak(){
System.out.println (this.name + "正在叫");
}
}
public class Test {
public static void main(String[] args){
Dog dog = new Dog();
dog.name = "大黄";
dog.age = 1;
dog.eat();
dog.beak();
System.out.println ("=======");
Cat cat = new Cat();
cat.name = "虎";
cat.age = 2;
cat.eat();
cat.mimi();
}
}
以上代码中,Cat类和Dog类有许多相同的地方:
public String name;
public int age ;
public void eat() {
System.out.println (this.name + "正在吃饭");
}
这些相同的成员变量和方法能不能将他们提取出来,放在一个共用的类当中。
当我们想实现这种方法时,这就要用到继承的关键字extends。
这是继承的写法。
public class 子类 extends 父类{
}
先放代码:
public class Animal {
public String name;
public int age ;
public void eat() {
System.out.println (this.name + "正在吃饭");
}
public class Dog extends Animal {
public void beak(){
System.out.println (this.name + "正在叫");
}
}
public class Cat extends Animal{
public void mimi(){
System.out.println (this.name + "正在叫");
}
}
public class Test {
public static void main(String[] args){
Dog dog = new Dog();
dog.name = "大黄";
dog.age = 1;
dog.eat();
dog.beak();
System.out.println ("=======");
Cat cat = new Cat();
cat.name = "虎";
cat.age = 2;
cat.eat();
cat.mimi();
}
}
这样,可以通过继承,让子类调用父类的成员。继承之后,子类可以使用父类中的成员,子类在实现时只需关心自己成员即可。
注意:子类里面一定要有自己的变量!不然父类定义的没有意义
换个简单点的例子:
public class Derievd extends Base {
public int c = 3;
public void func(){
Derievd derievd = new Derievd();
System.out.println (a);
System.out.println (b);
System.out.println (c);
}
}
public class Base {
public int a = 1;
public int b = 2;
}
public class Test {
public static void main(String[] args) {
Derievd derievd = new Derievd();
derievd.func();
}
}
运行结果 :
这之中,a、b是Derievd自己的成员变量,c是从Base中继承过来的成员变量这时可以看成属于Derievd,用this.引用c也是属于Derievd。
我们改一下看看会有什么变化:
public class Derievd extends Base {
public int c = 3;
public int a =100;
public void func(){
Derievd derievd = new Derievd();
System.out.println (this.a);
System.out.println (this.b);
System.out.println (this.c);
}
}
public class Base {
public int a = 1;
public int b = 2;
}
public class Test {
public static void main(String[] args) {
Derievd derievd = new Derievd();
derievd.func();
}
}
运行结果:
可知,用this.调用子类和父类有同名变量时候,优先调用子类的变量。当想调用父类的变量时候要用super.来调用父类的成员。
重写
在父类与子类里面,有方法相同;参数列表(个数、类型、顺序)相同;返回值相同,时候,我们称这个方法发生了重写。
public class Animal {
public String name;
public int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(this.name + "正在吃饭");
}
}
public class Dog extends Animal {
public Dog(String name,int age){
super(name,age);
}
public void eat(){
System.out.println ( this.name +"正在吃");
}
}
public class Test {
public static void main(String[] args){
Animal animal = new Dog("张三",12);
animal.eat();
}
上面方法就构成了重写:
通过向上转型父类的引用,打印出来子类和父类中被重写的方法。我们可以认为被重写的方法子类的地址传到了父类的方法中。
ps:@Override 看到这个符号就是提示你这个方法被重写了。
这种调用父类方法打印子类的方法的叫动态绑定。
理解动态绑定,是后续学习多态的基础。
注意:
1.不能重写静态方法。
2.方法不能被final修饰(final有不可变性,无法被重写)
3子类权限要大于等于父类权限。
4.private修饰的方法不能被重写(封装)
5.被重写的方法返回值类型可以不同,但是必须是具有父子关系的。
重写设计原则
对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容, 并且添加或者改动新的内容。
其他
静态绑定:在编译时,根据所传递实参类型就确定了具体调用那个方法。(重载)
动态绑定:在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。(重写)
向上转型.直接赋值
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
Animal animal = new Dog("张三",12);
animal.eat();
父类类型的引用子类对象,直接调用父类方法。
缺点:只能调用父类自己的方法。
向下转型
将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。
Java中为了提高向下转型的安全性,引入 了 instanceof ,如果该表达式为true,则可以安全转换。
if(animal instanceof Dog){
cat = (Dog)animal;
Dog.eat();
}