Java基础---类的继承
2015-11-09 14:04
706 查看
在Java中,被继承的类叫超类(superclass),继承超类的类叫子类(subclass)。子类继承了超类中所有的属性和方法。
有一对爷俩,爸爸和儿子,爸爸的眼睛是单眼皮,个子很高,头发很好,皮肤很黑,而儿子同样有他爸爸的一些特征,但是儿子的皮肤很白,双眼皮,戴眼镜,在外人看来他们是爷俩。儿子具有爸爸的所有特征,但是儿子的皮肤很白和戴眼睛这些是儿子自己所特有的,也是和爸爸不一样的地方。这个小例子正是日常生活里常见的。
换到Java里,类与类之间的关系,可以看成倒置的金字塔,爸爸在上面,儿子在下面。爸爸可能有多个儿子,但是一个儿子只能有一个爸爸,这在日常生活里也是如此。
示例:
关于继承时的覆盖有几点需要注意的:
1.构造函数:
当子类继承父类时,构造子类时会调用父类的构造函数,有三种情况:
(1)父类无构造函数或者一个无参数构造函数,子类若无构造函数或者有无参数构造函数,子类构造函数中不需要显式调用父类的构造函数,系统会自动在调用子类构造函数前调用父类的构造函数
(2)父类只有有参数构造函数,子类在构造方法中必须要显示调用父类的构造函数,否则编译出错
(3)父类既有无参数构造函数,也有有参构造函数,子类可以不在构造方法中调用父类的构造函数,这时使用的是父类的无参数构造函数
2.方法
(1)子类覆盖父类的方法,必须有同样的参数返回类型,否则编译不能通过
(2)子类覆盖父类的方法,在jdk1.5后,参数返回类可以是父类方法返回类的子类
(3)子类覆盖父类方法,可以修改方法作用域修饰符,但只能把方法的作用域放大,而不能把public修改为private
(4)子类方法能够访问父类的protected作用域成员,不能够访问默认的作用域成员
(5)子类的静态方法不能隐藏同名的父类实例方法
(6)java与C++一样,继承的方法具有多态性
3.成员
成员比较简单,子类覆盖父类成员时,各自的方法中调用的是各自方法中的成员变量
那么什么时候需要使用覆盖呢?
当子类需要父类的功能,而且子类在该功能的基础上增加一些自己的特点。示例:
还有,类加载器在加载子类时,会先加载父类,也就是会先初始化父类,并且子类会执行父类的构造方法。
再说个有关继承的关键字:final
因为继承有个不好的地方,就是打破了java的封装性,你想继承什么类就继承什么类怎么行呢? 于是就出现了final关键字。
它的作用有: 可以修饰类,方法,变量。 被修饰的类不能被继承,被修饰的方法不能被覆盖,被修饰的变量就成了常量。也就是被它修饰的东西就是最终端。
抽象类:
抽象类定义:顾名思义,就是抽象的类。 没有方法的方法体是抽象方法,包含抽象方法的类就是抽象类。
抽象类的特点:它有自己特有的修饰,用abstract来修饰。它只是声明了方法,却没有具体的方法体。
因为没有方法体所以不能被实例化,那么有什么用呢? 可以通过继承,覆盖里面抽象的方法,就行了。
抽象类和一般类的区别:
1.一般类不能定义抽象方法,可以定义非抽象方法,抽象类可以定义抽象方法,也可以定义非抽象方法。
2.一般类可以实例化,抽象不能被实例化。
因为程序员和经理都是雇员,存在着一些一样的特征。进行抽取。
接口:
理解了抽象类之后理解接口就简单了。 接口就是非常抽象的抽象类。也就是当抽象类中的方法都是抽象的时候,它就成了接口。
格式:interface{}
由于接口是完全抽象的,所以它和抽象类一样,不能被直接实例化。也需要被别的类实现。而且当它被别的类重写时,所有的方法由于都是抽象的,因而必须所有方法都重写,否则一样不能被实例化。因为只要有抽象方法存在,那个类就是个抽象类。
接口不是类。 类和类之间是继承关系,类和接口之间是实现关系。 之间说过继承只能但继承,因为有可能方法重复而带来一系列问题。 类却可以实现多个接口却不会有什么问题,因为接口的方法都是抽象的,即使有重名的方法,当你实现它的时候你也需要去重写定义它,就不存在多继承时出现的问题。 接口的出现避免了但继承的局限性。
这样一个类在继承一个类的同时,还是实现多个接口。
示例:
多态:
某一类事物的多种存在形态。
父类或者接口的引用指向或者接收自己的子类对象,好处是提高了程序的扩展性。
成员变量
编译时:参考因引用型变量所属的类中是否有调用的成员变量,没有就不能通过
成员函数
编译看左边,运行看右边
静态函数
编译和运行都取决于左边
内部类:
内部类是在一个外部类的内部再定义一个类。类名不需要和文件夹相同
成员内部类:
作为外部类的成员,好处是可以直接调用外部类中的所有方法和成员,包括private。
注意:内部类中不能含有static的变量和方法,原因很简单,因为static优先存在,而内部类需要在外部类存在了才创建。
示例:
局部内部类:
是定义在方法和作用域的内部类
运行结果:
show...9,4
匿名内部类:
如果满足下面的一些条件,使用匿名内部类是比较合适的:
1.只用到类的一个实例
2.类在定义后马上用到
3.类非常小,最好在4行代码以内
4.给类命名并不会导致你的代码更容易理解
注意:
1.匿名内部类不能有构造方法
2.匿名内部类不能定义任何静态成员,方法,类
3.匿名内部类不能是public protected private static
4.只能创建匿名内部类的一个实例
5.一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类
有一对爷俩,爸爸和儿子,爸爸的眼睛是单眼皮,个子很高,头发很好,皮肤很黑,而儿子同样有他爸爸的一些特征,但是儿子的皮肤很白,双眼皮,戴眼镜,在外人看来他们是爷俩。儿子具有爸爸的所有特征,但是儿子的皮肤很白和戴眼睛这些是儿子自己所特有的,也是和爸爸不一样的地方。这个小例子正是日常生活里常见的。
换到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 { }
相关文章推荐
- Spring配置动态数据源
- 【Eclipse】打开文件所在文件夹的插件
- Java的身份证号码工具类
- Java设计模式(1)-单例模式
- spring源码阅读笔记
- Java方法excel文件转换成xml文件
- eclipse 显示 空格 .回车符号,去掉相应的符号
- JAVA项目编码规范参考
- 中文分词系统NLPIR(2015版)的Java接口使用学习
- Java:FileOutputStream与FileWriter的区别
- java中对象的序列化和反序列化
- java.lang.NoClassDefFoundError
- java基础学习笔记(7)
- java基础学习笔记(6)
- Mac JAVA 环境变量和 Maven环境变量
- SPRING 简介
- java记——连接两个字符串
- Eclipse中自动添加注释
- Springmvc的执行流程和mybatis执行流程
- Java使用base64加解密