Java基础---类的继承

来源:互联网 发布:淘宝卖家充快递单号 编辑:程序博客网 时间:2024/05/22 06:12

在Java中,被继承的类叫超类(superclass),继承超类的类叫子类(subclass)。子类继承了超类中所有的属性和方法。
有一对爷俩,爸爸和儿子,爸爸的眼睛是单眼皮,个子很高,头发很好,皮肤很黑,而儿子同样有他爸爸的一些特征,但是儿子的皮肤很白,双眼皮,戴眼镜,在外人看来他们是爷俩。儿子具有爸爸的所有特征,但是儿子的皮肤很白和戴眼睛这些是儿子自己所特有的,也是和爸爸不一样的地方。这个小例子正是日常生活里常见的。
   换到Java里,类与类之间的关系,可以看成倒置的金字塔,爸爸在上面,儿子在下面。爸爸可能有多个儿子,但是一个儿子只能有一个爸爸,这在日常生活里也是如此。
示例:
class Test {public Test(){  //构造方法}protected void doSomething(){   //成员方法}protected Test doIt(){//方法返回值类型为Test类型return new Test();}}class Test2 extends Test //继承父类{public Test2(){    //构造方法super();        //调用父类构造方法super.doSomething();//调用父类成员方法}public void doSomethingnew(){ //新增方法}public void doSomething(){  //重写父类方法}protected Test2 doIt2(){   //重写父类方法return new Test2();}}
注意:一个超类可以有多个子类,但是一个子类却只能有一个父类。(这点和C语言不同,java是通过接口来实现多继承的,这样可以避免方法重复时一系列的问题)

关于继承时的覆盖有几点需要注意的:
  1.构造函数:
 当子类继承父类时,构造子类时会调用父类的构造函数,有三种情况:
   (1)父类无构造函数或者一个无参数构造函数,子类若无构造函数或者有无参数构造函数,子类构造函数中不需要显式调用父类的构造函数,系统会自动在调用子类构造函数前调用父类的构造函数
   (2)父类只有有参数构造函数,子类在构造方法中必须要显示调用父类的构造函数,否则编译出错
 (3)父类既有无参数构造函数,也有有参构造函数,子类可以不在构造方法中调用父类的构造函数,这时使用的是父类的无参数构造函数
  2.方法
  (1)子类覆盖父类的方法,必须有同样的参数返回类型,否则编译不能通过
  (2)子类覆盖父类的方法,在jdk1.5后,参数返回类可以是父类方法返回类的子类
  (3)子类覆盖父类方法,可以修改方法作用域修饰符,但只能把方法的作用域放大,而不能把public修改为private
   (4)子类方法能够访问父类的protected作用域成员,不能够访问默认的作用域成员
  (5)子类的静态方法不能隐藏同名的父类实例方法
  (6)java与C++一样,继承的方法具有多态性
  3.成员
   成员比较简单,子类覆盖父类成员时,各自的方法中调用的是各自方法中的成员变量

那么什么时候需要使用覆盖呢?
当子类需要父类的功能,而且子类在该功能的基础上增加一些自己的特点。示例:
class Phone6 {void call(){}void show(){System.out.println("number");}}class Phone6s extends Phone6    {void show(){System.out.println("name");System.out.println("address"); //子类新增的功能super.show();  //调用父类方法功能}}class ExtendDemo{public static void main(String[] args){Phone6s p = new Phone6s();  //创建子类p.show();  //调用子类方法}}
注意:父类中的私有方法和static方法不能被覆盖,而且覆盖时子类的权限要大于或者等于父类的的权限。
还有,类加载器在加载子类时,会先加载父类,也就是会先初始化父类,并且子类会执行父类的构造方法。

再说个有关继承的关键字:final
因为继承有个不好的地方,就是打破了java的封装性,你想继承什么类就继承什么类怎么行呢? 于是就出现了final关键字。
它的作用有: 可以修饰类,方法,变量。 被修饰的类不能被继承,被修饰的方法不能被覆盖,被修饰的变量就成了常量。也就是被它修饰的东西就是最终端。

抽象类:
抽象类定义:顾名思义,就是抽象的类。 没有方法的方法体是抽象方法,包含抽象方法的类就是抽象类。
抽象类的特点:它有自己特有的修饰,用abstract来修饰。它只是声明了方法,却没有具体的方法体。
因为没有方法体所以不能被实例化,那么有什么用呢? 可以通过继承,覆盖里面抽象的方法,就行了。
抽象类和一般类的区别:
1.一般类不能定义抽象方法,可以定义非抽象方法,抽象类可以定义抽象方法,也可以定义非抽象方法。
2.一般类可以实例化,抽象不能被实例化。

因为程序员和经理都是雇员,存在着一些一样的特征。进行抽取。
//描述雇员。abstract class Employee{       private String name ;       private String id ;       private double pay ;      Employee(String name,String id, double pay){             this.name = name;             this.id = id;             this.pay = pay;      }       public abstract void work(); }//描述程序员class Programmer extends Employee{  //继承雇员      Programmer(String name,String id, double pay){             super(name,id,pay);      }       public void work(){ //实例化抽象方法            System.out.println("code..." );       }}//描述经理class Manager extends Employee{  //继承雇员      private int bonus ;            Manager(String name,String id, double pay,int bonus){             super(name,id,pay);             this.bonus = bonus;      }      public void work(){//实例化抽象方法            System.out.println("manage" );      }}



接口:
理解了抽象类之后理解接口就简单了。 接口就是非常抽象的抽象类。也就是当抽象类中的方法都是抽象的时候,它就成了接口。
格式:interface{}
由于接口是完全抽象的,所以它和抽象类一样,不能被直接实例化。也需要被别的类实现。而且当它被别的类重写时,所有的方法由于都是抽象的,因而必须所有方法都重写,否则一样不能被实例化。因为只要有抽象方法存在,那个类就是个抽象类。
接口不是类。 类和类之间是继承关系,类和接口之间是实现关系。  之间说过继承只能但继承,因为有可能方法重复而带来一系列问题。 类却可以实现多个接口却不会有什么问题,因为接口的方法都是抽象的,即使有重名的方法,当你实现它的时候你也需要去重写定义它,就不存在多继承时出现的问题。  接口的出现避免了但继承的局限性。 这样一个类在继承一个类的同时,还是实现多个接口。
示例:
interface A{public void show();}interface B{public void show();}abstract class C{public void method(){}}class D extends C implements A,B{public void show(){System.out.println("Ashow");}public void method(){System.out.println("Cmethod");}}class interfaceDemo{public static void main(String[] args){D d = new D();d.show();d.method();}}

多态:
某一类事物的多种存在形态。
父类或者接口的引用指向或者接收自己的子类对象,好处是提高了程序的扩展性。
成员变量
编译时:参考因引用型变量所属的类中是否有调用的成员变量,没有就不能通过
成员函数
编译看左边,运行看右边
静态函数
编译和运行都取决于左边
abstract class Animal{       abstract void eat();}//狗猫猪都继承了抽象类动物类class Dog extends Animal{       void eat(){            System.out.println("啃骨头");       }       void lookHome(){            System.out.println("看家");       }}class Cat extends Animal{       void eat(){            System.out.println("吃鱼");       }       void catchMouse(){            System.out.println("抓老鼠");       }}class Pig extends Animal{       void eat(){            System.out.println("饲料");       }       void gongdi(){            System.out.println("拱地");       }}class DuoTaiDemo{       public static void main(String[] args){            Cat c = new Cat();            Dog d = new Dog();             method(c);//向方法中传入cat对象,向上转型             method(d);//向上转型             method(new Pig());       }       public static void method(Animal a){            a.eat();       }}

内部类:
内部类是在一个外部类的内部再定义一个类。类名不需要和文件夹相同

成员内部类:
  作为外部类的成员,好处是可以直接调用外部类中的所有方法和成员,包括private。
 注意:内部类中不能含有static的变量和方法,原因很简单,因为static优先存在,而内部类需要在外部类存在了才创建。
示例:
public class Outer{public static void main(String[] args){Outer outer = new Outer();Outer.Inner inner = outer.new Inner();//创建成员内部类对象inner.print("Outer.new"); //调用内部类的方法inner = outer.getInner(); inner.print("Outer.get");//调用外部类的成员方法}public Inner getInner(){return new Inner();}public class Inner //成员内部类{public void print(String str)//内部类的方法{System.out.println(str);}}}
运行结果:


局部内部类:
是定义在方法和作用域的内部类

class Outer{int num = 3;void method(final int y){final int x = 9;//被final修饰的变量不会改值class Inner //定义在成员方法内部的内部类{void show(){System.out.println("show..."+x+","+y);}}Inner in = new Inner();//创建了方法内部的内部类in.show();//调用内部类的方法}}class InnerClassDemo{public static void main(String[] args){new Outer().method(4); //实现并调用类中的方法}}

运行结果:
show...9,4

匿名内部类:
如果满足下面的一些条件,使用匿名内部类是比较合适的:
1.只用到类的一个实例
2.类在定义后马上用到
3.类非常小,最好在4行代码以内
4.给类命名并不会导致你的代码更容易理解

注意:
1.匿名内部类不能有构造方法
2.匿名内部类不能定义任何静态成员,方法,类
3.匿名内部类不能是public protected private static
4.只能创建匿名内部类的一个实例
5.一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类
public class AnnInnerClassDemo{public static void main(String[] args){Demo demo = new Demo(){};//匿名内部类}}class Demo{}
{}为类体,只有类体,没有类名
class AnnInnerClassDemo2{public static void main(String[] args){/*1.匿名内部类new Demo(){}是对Demo的继承,   并同时实例化   new Demo(){}是Demo子类实例,是一个对象  2.类体中可以声明大部分类的功能,比如覆盖的toString()方法        */Demo2 demo = new Demo2(){};//匿名内部类Demo2 demo1 = new Demo2(){public String toString(){return "i am demo1";}};System.out.println(demo);System.out.println(demo1);}}class Demo2{}





0 0