继承与多态
一、继承条件下的构造方法的调用
- class Grandparent
- {
- public Grandparent()
- {
- System.out.println("GrandParent Created.");
-
- }
- public Grandparent(String string)
- {
- System.out.println("GrandParent Created.String:" + string);
-
- }
- }
- class Parentt extends Grandparent
- {
- public Parentt()
- {
- super("Hello.Grandparent.");
- System.out.println("Parent Created");
-
- // super("Hello.Grandparent.");
- }
- public Parentt(String s)
- {
- System.out.println("Parent Created.String:"+s);
- }
- }
- class Childd extends Parentt
- {
- public Childd()
- {
- super("Hello.Parent.");
- System.out.println("Child Created");
- }
- }
- public class TestInherits
- {
- public static void main(String args[])
- {
- Childd c = new Childd();
-
- }
- }
复制代码
输出:
GrandParent Created. Parent Created.String:Hello.Parent. Child Created
在构造子类的方法之前会先构造父类的方法,如果是多级继承,会先执行最顶级父类的构造方法,然后依次执行各级个子类的构造方法。若想在子类中调用父类的有参构造方法,必要在子类的构造方法的第一行加上super方法,注意:只能是第一行
为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来? - 因为子类继承自父类,会相沿父类的东西(没被覆盖的函数以及可见的成员变量等),而这些东西子类是没有的,必要先初始化父类才气被使用。<br />构造一个对象,先调用其构造方法,来初始化其成员函数和成员变量。<br />子类拥有父的成员变量和成员方法,如果不调用,则从父类继承而来的成员变量和成员方法得不到准确的初始化。<br />不能反过来调用也是这个原因,因为父类根本不知道子类有神魔变量而且这样一来子类也得不到初始化的父类变量,导致步伐运行堕落!<br />
复制代码
二、不答应继承的类
不可变的“类”有何作用:
①可方便和安全的用于多线程的情况中
②访问他们不用加锁,可高性能的执行
- public final class Address
- {
- private final String detail;
- private final String postCode;
- //在构造方法里初始化两个实例属性
- public Address()
- {
- this.detail = "";
- this.postCode = "";
- }
- public Address(String detail , String postCode)
- {
- this.detail = detail;
- this.postCode = postCode;
- }
- //仅为两个实例属性提供getter方法
- public String getDetail()
- {
- return this.detail;
- }
- public String getPostCode()
- {
- return this.postCode;
- }
- //重写equals方法,判定两个对象是否相等。
- public boolean equals(Object obj)
- {
- if (obj instanceof Address)
- {
- Address ad = (Address)obj;
- if (this.getDetail().equals(ad.getDetail()) && this.getPostCode().equals(ad.getPostCode()))
- {
- return true;
- }
- }
- return false;
- }
- public int hashCode()
- {
- return detail.hashCode() + postCode.hashCode();
- }
- public static void main(String args[])
- {
- Address add=new Address("123","456");
- System.out.println(add.getDetail());
- System.out.println(add.getPostCode());
- Address arr=new Address("123","456");
- System.out.println(add.equals(arr));
-
- }
- }
复制代码
输出:
123 456 true
三、反汇编
- public class ExplorationJDKSource {
- /**
- * @param args
- */
- public static void main(String[] args) {
- System.out.println(new A());
- }
- }
- class A{}
复制代码
输出:
A@15db9742
我们用javap -c 来反编译该文件的.class文件,得到:
点进object里,发现tostring方法
public void main(object x)调用了String类的valueOf方法,
故而出现了这样的输出
三、神奇的“+”号和方法覆盖
- public class Fruit
- {
-
- public String toString()
- {
- return "Fruit toString.";
- }
- public static void main(String args[])
- {
- Fruit f=new Fruit();
- System.out.println("f="+f);
- System.out.println("f="+f.toString());
- }
- }
复制代码
在输出字符串+对象时,会隐式的调用tostring()的方法
方法的覆盖:要求子类和父类的方法一样,并且实现在子类中调用父类的被覆盖的方法
- class ABC
- {
- public void print()
- {
- System.out.println("Parent print");
- }
- }
- public class test extends ABC{
- public void print()
- {
- super.print();
- System.out.println("Children print");
- }
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- test t1=new test();
- t1.print();
- }
- }
复制代码
输出:
Parent print Children print
使用super()的方法调用父类的对象,然后再调用父类的覆盖方法
覆盖的语法规则:
四、如何判定对象是否可以转换
- public class TestInstanceof
- {
- public static void main(String[] args)
- {
- //声明hello时使用Object类,则hello的编译范例是Object,Object是全部类的父类
- //但hello变量的现实范例是String
- Object hello = "Hello";
- //String是Object类的子类,所以返回true。
- System.out.println("字符串是否是Object类的实例:" + (hello instanceof Object));
- //返回true。
- System.out.println("字符串是否是String类的实例:" + (hello instanceof String));
- //返回false。
- System.out.println("字符串是否是Math类的实例:" + (hello instanceof Math));
- //String实现了Comparable接口,所以返回true。
- System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable));
- String a = "Hello";
- //String类既不是Math类,也不是Math类的父类,所以下面代码编译无法通过
- //System.out.println("字符串是否是Math类的实例:" + (a instanceof Math));
- }
- }
复制代码
输出:
字符串是否是Object类的实例:true 字符串是否是String类的实例:true 字符串是否是Math类的实例:false 字符串是否是Comparable接口的实例:true
范例转换事例:
- import java.net.InterfaceAddress;
- class Mammal{}
- class Dog extends Mammal {}
- class Cat extends Mammal{}
- public class TestCast
- {
- public static void main(String args[])
- {
- Mammal m;
- Dog d=new Dog();
- Cat c=new Cat();
- m=d;
- //d=m;
- d=(Dog)m;
- //d=c;
- //c=(Cat)m;
- System.out.println("good");
- }
- }
复制代码
将子类dag赋值给基类m,可以实现,而将基类赋值给d必要举行逼迫范例转换,两个子类之间不能举行转换,m已经是Dog类,不能再被逼迫转换为Cat类
五、失常的类
- public class ParentChildTest {
- public static void main(String[] args) {
- Parent parent=new Parent();
- parent.printValue();//100
- Child child=new Child();
- child.printValue();//200
-
- //父类变量去引用子类对象
- parent=child;
-
- parent.printValue();//调用子类的方法200
-
- //如果子类被当作父类使用,则通过子类访问的字段是父类的!
- parent.myValue++;
- System.out.println(parent.myValue);//101
- parent.printValue();//200
-
- ((Child)parent).myValue++;
- parent.printValue();
-
- }
- }
- class Parent{
- public int myValue=100;
- public void printValue() {
- System.out.println("Parent.printValue(),myValue="+myValue);
- }
- }
- class Child extends Parent{
- public int myValue=200;
- public void printValue() {
- System.out.println("Child.printValue(),myValue="+myValue);
- }
- }
复制代码
输出:
Parent.printValue(),myValue=100 Child.printValue(),myValue=200 Child.printValue(),myValue=200 101 Child.printValue(),myValue=200 Child.printValue(),myValue=201
前两个输出没问题,将子类赋值给基类对象,基类对象指向子类对象,调用的是子类的方法,故而输出第三条, - parent.myValue++;就是将子类当成父类来使用,通过子类访问的字段是父类的所以,当输出myvalue时是101,是父类的值+1;<br />末了将基类逼迫转换成子类后,将value++,此时访问的才是子类的字段,故而输出结果为201.
复制代码六、多态
- package zoo4;
- import java.util.Vector;
- public class Zoo {
- public static void main(String args[]) {
- Feeder f = new Feeder("小李");
- Vector<Animal> ans = new Vector<Animal>();
- //豢养员小李喂养一只狮子
- ans.add(new Lion());
- //豢养员小李喂养十只猴子
- for (int i = 0; i < 10; i++) {
- ans.add(new Monkey());
- }
- //豢养员小李喂养5只鸽子
- for (int i = 0; i < 5; i++) {
- ans.add(new Pigeon());
- }
- f.feedAnimals(ans);
- }
- }
- class Feeder {
- public String name;
- Feeder(String name) {
- this.name = name;
- }
- public void feedAnimals(Vector<Animal> ans) {
- for (Animal an : ans) {
- an.eat();
- }
- }
- }
- abstract class Animal {
- public abstract void eat();
- }
- class Lion extends Animal {
- public void eat() {
- System.out.println("我不吃肉谁敢吃肉!");
- }
- }
- class Monkey extends Animal {
- public void eat() {
- System.out.println("我什么都吃,尤其喜好香蕉。");
- }
- }
- class Pigeon extends Animal {
- public void eat() {
- System.out.println("我要减肥,所以天天只吃一点大米。");
- }
- }
复制代码
输出:
我不吃肉谁敢吃肉! 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我什么都吃,尤其喜好香蕉。 我要减肥,所以天天只吃一点大米。 我要减肥,所以天天只吃一点大米。 我要减肥,所以天天只吃一点大米。 我要减肥,所以天天只吃一点大米。 我要减肥,所以天天只吃一点大米。
通过界说一个抽象类anmial,来控制所以动物吃的功能,通过vector这个可变长数组,来控制动物的增减,终极实现当再加入其他差别的动物时,用较少的修改来完成动物的添加。
除了可以用抽象类来实现,还可以使用接口的情势来实现
- package zoo5;
- import java.util.Vector;
- public class Zoo {
- public static void main(String args[]) {
- Feeder f = new Feeder("小李");
- Vector<Animal> ans = new Vector<Animal>();
- //豢养员小李喂养一只狮子
- ans.add(new Lion());
- //豢养员小李喂养十只猴子
- for (int i = 0; i < 10; i++) {
- ans.add(new Monkey());
- }
- //豢养员小李喂养5只鸽子
- for (int i = 0; i < 5; i++) {
- ans.add(new Pigeon());
- }
- f.feedAnimals(ans);
- }
- }
- class Feeder {
- public String name;
- Feeder(String name) {
- this.name = name;
- }
- public void feedAnimals(Vector<Animal> ans) {
- for (Animal an : ans) {
- an.eat();
- }
- }
- }
- interface Animal {
- public void eat();
- }
- class Lion implements Animal {
- public void eat() {
- System.out.println("我不吃肉谁敢吃肉!");
- }
- }
- class Monkey implements Animal {
- public void eat() {
- System.out.println("我什么都吃,尤其喜好香蕉。");
- }
- }
- class Pigeon implements Animal {
- public void eat() {
- System.out.println("我要减肥,所以天天只吃一点大米。");
- }
- }
复制代码
抽象类与抽象方法
抽象类的三种方法:
抽象类不能用来创建对象,一样寻常用他来引用子类的对象
接口:
接口的使用:
接口的扩充:
接口与抽象类的区别:
来源:https://www.cnblogs.com/xiaofengzai/p/11728626.html |