您的位置:首页 > 编程语言 > Java开发

Java基础---类的继承

2015-11-09 14:04 706 查看
在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
{
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: