天天看点

黑马程序员——java基础——面向对象(二)

面向对象的另外两个特征:继承和多态

继承:

1,提高了代码的复用性。

2,让类与类之间产生了关系。有了这个关系,才有了多态的特性。

注意:千万不要为了获取其他类的功能,简化代码而继承。

必须是类与类之间有所属关系才可以继承。

子父类出现后,类成员的特点:

类中成员:

1,变量。

2,函数。

3,构造函数。

1,变量

如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this,子类要访问父类中的同名变量,用super。

super的使用和this的使用几乎一致。

this代表的是本类对象的引用。

super代表的是父类对象的引用

2,子父类中的函数。

当子类出现和父类一模一样的函数时,

当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。

这种情况是函数的另一个特性:重写(覆盖)

当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖,保留父类的功能定义,并重写功能内容。

覆盖:

1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。

2,静态只能覆盖静态

重载:只看同名函数的参数列表。

重写:子父类方法要一模一样

3,子父类中的构造函数。

在对子类对象进行初始化时,父类的构造函数也会运行,

那是因为子类的构造函数默认第一行有一条隐式的语句 super();

super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();

当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。

当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。

但子类中至少会有一个构造函数会访问父类中的构造函数。、

class Fu
{
    int num = ;
    Fu()
    {
        System.out.println("Fu gouzao");
    }
    Fu(int x)
    {
        System.out.println("Fu..."+x);
    }
    void speak()
    {
        System.out.println("fu run");
    }
}

class Zi extends Fu
{
    int num =  ;
    Zi()
    {
        //super(); 子类的构造函数在第一行都会有一个默认的super()
        super();//可以手动初始化
        System.out.println("Zi gouzao");
    }
    Zi(int x)
    {
        //super();
        System.out.println("Zi....."+x);
    }
    void show()
    {
        System.out.println(super.num);//若不写super 则默认为this
    }
    void speak()//覆盖父类中的方法  必须和父类是一摸一样的,权限要大于等于父类的,private除外
    {
        System.out.println("Zi run");
    }
}
class ExtendsDemo 
{
    public static void main(String[] args) 
    {
        //Zi z = new Zi();
        Zi z1 = new Zi();
        //z.show();
        z1.speak();
    }
}
           

final 可以用来修饰类,函数和变量

1.修饰类后 该类不能被继承

2.修饰函数(方法)后,该方法不能被复写

3.修饰变量后,该变量就会成为一个常量 一般定义 public static final double MY_PI = 3.14;

4.在局部的内部类中,只能访问该局部被final修饰的局部变量。

抽象类的特点;

1.抽象方法所在的类是抽象的

2.抽象类和抽象方法必须用abstract 所修饰

3.抽象类不能用new建立对象,因为没有方法实体,并且建立对象毫无意义

4.抽象类中的方法必须被复写后,然后通过建立子类对象来使用

5.复写抽象类中的方法只要有一个没有被复写,那么其子类就是抽象的

abstract 关键字,和哪些关键字不能共存。

final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。

private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。而抽象方法出现就是需要被复写。

static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。但抽象方法运行没意义。

abstract class Student
{
    abstract void study();
    void sleep()
    {
        System.out.println("躺着");
    }
}
class Student1 extends Student
{
    void study()
    {
        System.out.println("study");
    }
}

class AbstractDemo 
{
    public static void main(String[] args) 
    {
        new Student1().study();
    }
}
           

java中实现多继承是通过接口来实现的,因为接口中的方法都没有方法实体

接口和接口之间是继承关系,可以是多继承

类与类之间是是继承关系,可以多层继承,不能多继承

类与接口之间是实现关系,可以多实现,因为接口中的方法都没有方法实体

interface 中的变量都是常量 固定格式为: public static final int x = 4 ;

方法都是抽象的 固定格式为 public abstract void();

接口不能创建对象,因为它是抽象的,它必须被其子类把所有的抽象方法复写后然后通过子类来创建对象

接口主要是用来实现功能的扩展

interface Inter
{
    public static final int NUM = ;
    public abstract void show();
}

interface InterA
{
    public abstract void show();
}

class Demo
{
    public void function(){}
}

class Test extends Demo implements Inter,InterA
{
    public void show(){}
}

interface A
{
    void methodA();
}
interface B extends A
{
    void methodB();
}

interface C extends B,A
{
    void methodC();
}

class D implements C
{
    public void methodA(){}
    public void methodC(){}
    public void methodB(){}
}
           

抽象类和接口的异同:

相同点:

1,都可以在内部定义抽象方法。

2,通常都在顶层。

3,都不可以实例化,都需要子类来实现。

不同点:

1,抽象类中可以定义抽象方法和非抽象方法,而接口中只能定义抽象方法。

2,接口的出现可以多实现。抽象类只能单继承。

也就是说:接口的出现避免了单继承的局限性。

3,继承和实现的关系不一致。

多态:

1.多态的体现

父类的引用指向子类的对象,父类的引用可以接收子类的对象

2.多态的前提

类与类之间必须有关系,要么继承,要么实现,要有覆盖的动作

3.多态的好处

大大的提高了程序的扩展性

4.多态的弊端

提高了扩展性,但是只能使用父类的引用访问父类中的成员

5.多态的应用

多态中,非静态成员函数的特点

在编译时期参阅引用变量所属类中有没有这个方法,如果有,则编译通过,若没有,则编译失败,在运行时期参阅对象所属类中的方法

在编译时期看左边,运行时期看右边

多态中,静态成员函数的特点

无论编译和运行都看左边所属的类(因为静态是随着类的加载而加载,优先于对象而存在,可以直接类名调用,并且是静态绑定在类中)

多态中,静态和非静态成员变量的特点

无论编译和运行都看左边所属的类

/*
主板的多态事例
有一个主板,它应该具有一些功能,但为了功能有更好的扩展性,
我们会定义一个接口,主板可以使用这个接口,然后符合这个接口的功能都能实现
*/
class MainBoard
{
    public void run()
    {
        System.out.println("MainBoard run");
    }
    public void usePCI(PCI p)//主板使用接口 接口类型的引用指向子类对象,多态
    {
        //存在对象时,才具有开关的功能
        if(p!=null)
        {
            p.open();
            p.close();
        }
    }
}
/*
定义一个接口,它只有开和关的动作
这样主板的程序不需要改变,接口也是固定的
若需要扩展新的功能,只需实现接口即可
*/
interface PCI
{
    public void open();
    public void close();
}
class SoundCard implements PCI
{
    public void open()
    {
        System.out.println("SoundCard run");
    }
    public void close()
    {
        System.out.println("SoundCard close");
    }
}
class Mouse implements PCI
{
    public void open()
    {
        System.out.println("Mouse open");
    }
    public void close()
    {
        System.out.println("Mouse close");
    }
}
class DuoTaiDemo
{
    public static void main(String[] args) 
    {
        MainBoard mb = new MainBoard();
        mb.run();
        mb.usePCI(new SoundCard());
        mb.usePCI(new Mouse());
    }
}
           

内部类:

1.内部类可以直接访问外部类中的成员,包括私有,之所以能够访问,就是因为外部类的成员前省略了 外部类名.this

2.外部类想要访问内部类中的成员必须建立内部类中的对象

3.别的类想要访问内部类,应该先要建立外部类的对象,然后在建立内部类的对象

格式为:外部类名.内部类名 x = new 外部类名().new 内部类名();

内部类在外部类的成员位置上,所以可以被static private 修饰

静态内部类访问外部类中的成员时,外部类的成员必须是静态的

外部类中的静态方法访问内部类时,内部类也必须是静态的

内部类中的方法若是静态的则内部类必须是静态的

一个静态内部类访问另一个内部类时,那个内部类必须是静态的

内部类定义在局部时。

1.不可以被成员修饰符所修饰,如 static private 等

2.可以直接访问外部类中的成员,因为还带有外部的引用

但是不可以访问它所在局部类中的变量,只能访问被final修饰的局部变量

class Outer
{
    private static int x = ;
    void show()
    {
        new Inner().function();
        System.out.println("Outer run..."+x);
    }
    static class Inner
    {

        //int x = 2 ;
        void function()
        {
            //int x = 3 ;
            System.out.println("Inner run....."+x);
        }
    }
    static class Inner2
    {
        void show1()
        {
            new Inner().function();
            System.out.println("Inner2 run");
        }
    }
    public static void method()
    {
        new Inner().function();
        System.out.println("method run");
    }
}
class InnerClassDemo 
{
    public static void main(String[] args) 
    {
        new Outer.Inner2().show1();//内部类是静态但其方法不是静态时这样调用
        //new Outer().new Inner2().show1();//内部类不是静态并且方法也不是静态时这样调用
        //Outer.Inner.function();//内部类是静态的并且其方法也是静态的
    }
}
           

匿名内部类:

1,匿名内部类其实就是内部类的简写格式。

2,定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。

3,匿名内部类的格式: new 父类或者接口(){定义子类的内容}

4,其实匿名内部类就是一个匿名子类对象。可以理解为带内容的对象。

5,匿名内部类中定义的方法最好不要超过3个。

interface Inner
{
    void method();
}
class InnerClassTest
{
    public static void main(String[] args) 
    {

        Test.function().method();
        /*
        1.Test可以直接调用function(),说明在Test类中有一个静态的function()方法
        2.Test.function()可以调用method(),首先说明Test类实现了Inner接口,复写了method(),并且Test.function() 还是一个对象并且对象是Inner的子类
        */
    }
}
class Test 
{
    //不用匿名内部类补足代码
    public static Inner function()
    {
        return new Inter();
    }
    static class Inter implements Inner
    {
        public void method()
        {
            System.out.println("jajaja");
        }
    }

    //通过匿名内部类补足代码
    /*public static Inner function()
    {
        return new Inner()
        {
            public void method()
            {
                System.out.println("method run");
            }
        };
    }
    */
}

//需求:在一个方法不属于任何类的情况下调用它
class In
{
    public static void main(String[] args)
    {
        new Object()//Object是任何类的父类
        {
            public void show()
            {
                System.out.println("show");
            }
        }.show();
    }
}