05.面向对象(二)【单例】【继承】【多态】【接口】【final】【内部类】

来源:互联网 发布:java 验证身份证 编辑:程序博客网 时间:2024/06/16 07:45


1.方案-建立数组工具类,并在另一个类中调用

    思路:数组操作一般有遍历,获取最值,排序,置换位置,获取元素索引等。如果有数组操作时每次都要写这些方法,代码将会显得冗长,而且不利于提高代码复用性。我们可以将这个操作动作封装在一个类中,以后有数组要进行相关操作时,可以直接调用这个工具类中的方法。

   假设建立了一个数组工具类ArrayTool,里面封装了遍历,获取最值,排序,置换位置,获取元素索引这些数组操作方法。那么,另一个类ArrayTool就可以调用。

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)
  

class ArrayToolDemo {/*保证程序的独立运行。*/public static void main(String[] args) {int[] arr = {4,8,2,9,72,6};//调用ArrayTool工具类方法,获取最值int max = ArrayTool.getMax(arr);System.out.println("max="+max);//调用方法,将数组转成字符串String str = ArrayTool.arrayToString(arr);System.out.println(str);//调用选择排序方法ArrayTool.selectSort(arr);System.out.println(ArrayTool.arrayToString(arr));}

2.单例设计模式

 (1) 设计模式:就是解决问题的行之有效的方法。其实就是一种思想。

       每种模式解决一种问题。

      单例设计模式解决的问题:可以保证一个类在内存中的对象唯一性。

 (2)如何保证对象的唯一性呢?

      ①不允许其他程序创建该对象。

      ②在该类中创建一个本类对象。

      ③对外提供一个方法,使其获取该对象。

 

    步骤:

       ①创建一个类,私有化构造函数。

       ②通过new创建一个本类私有化的静态对象。

       ③创建一个公有的方法,返回该本类对象。

 (3)单例设计模式分为饿汉式和懒汉式。其实就是针对该本类对象什么时候加载进内存而言。

     ①饿汉式:类一加载,对象就已经存在了。

       开发时使用饿汉式,因为对象最终还是要加载。

代码如下:

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)    

//饿汉式public class SingleDemo {//在本类中创建实例对象private static SingleDemo singleDemo = new SingleDemo();//私有化构造函数private SingleDemo(){}//提供方法供外界访问对象public static SingleDemo getInstance() {return singleDemo;}}


     ②懒汉式:类刚加载进内存时,没有对象,调用方法时,再创建对象。       面试时使用懒汉时,涉及的知识点比较多。

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)      

//懒汉式public class SingleDemo1 {//先不创建对象private static SingleDemo1 singleDemo = null;//私有化构造函数private SingleDemo1(){}//提供方法供外界访问对象,调用方法时才创建对象public static SingleDemo1 getInstance() {if(singleDemo == null)singleDemo = new SingleDemo1();return singleDemo;}}

3.继承(extends)

 (1)继承:指的是一个对象直接使用另一个对象的属性和方法。子类继承了父类的内容。这样子类就可以

不用自己写父类中已有的代码。

    Java中,默认所有类都可以扩展,但是可以用final关键字阻止其被继承。
继承时使用extends关键字来实现子类继承父类。

 

简单的代码示例:

  

class Person{String name;int age;}class Student extends/*继承*/ Person{//String name;//子类继承父类的内容,可以直接使用父类中的name和age//int age;void study(){System.out.println(name+"...student study.."+age);}}class Worker extends Person{//String name;//int age;void work(){System.out.println(name+"worker work"+age);}}class ExtendsDemo {public static void main(String[] args) {Student s = new Student();s.name= "zhangsan";s.age = 22;s.study();}}




 (2) 继承的好处:

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

          2)让类与类之间产生了关系,给多态提供了前提。

 (3)单继承与多继承:

      单继承:一个子类只能继承一个父类,不能有多个父类。

     多继承:一个子类可以直接继承多个父类。在java中是不允许的。因为如果多个父类中有相同的成员,会产生调用的不确定性。就会抛出异常。

     所以,java中支持单继承,不支持多继承。但对c++中的多继承机制进行改良,通过“多实现”的形式

来体现。

 (4)多层继承

     java支持多层(多重)继承。

     C继承B,B继承A。
      就会出现继承体系。

    

    当要使用一个继承体系时,
         1)查看该体系中的顶层类,了解该体系的基本功能。
         2)创建体系中的最子类对象,完成功能的使用。

 (5)什么时候定义继承呢?

     当类与类之间存在着所属关系的时候,就定义继承。xxx是yyy中的一种。 xxx extends yyy

     所属关系: is a 关系。

 

    注意:不要为了获取其它类的功能而简化代码的书写而继承,
    必须是类与类之间具有所属关系才能实现继承。

 (6)成员的特点:

     1)成员变量

        当本类的成员和局部变量同名时,用this来区分。
        当子父类的成员变量同名时用super来区分父类。

        this:代表一个本类对象的引用。
        super:代表一个父类的空间。

        this和super的用法很相似。

      2)成员函数(覆盖)

        当子父类中出现成员函数一模一样的情况,会运行子类的函数。
        这种现象,称为覆盖操作。这时函数在子父类中的特性。

  

        函数两个特性:
            ①重载。发生在同一个类中。overload
             ②覆盖。发生在子类中,子类方法覆盖父类的方法。覆盖也称为重写,覆写。override

 

       覆盖注意事项:
            1)子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限。

              (已学过的权限有:public,protected,private,默认等)
            2)静态只能覆盖静态,或被静态覆盖。

 

       什么时候使用覆盖操作?

            当对一个类进行子类的扩展时,子类需要保留父类的功能声明。
           但是要定义子类中该功能的特有内容时,就使用覆盖操作完成。

    3)构造函数

       子父类中的构造函数的特点:
            子类构造对象时,发现,访问子类的构造函数时,父类的构造函数也运行了。
            在子类构造函数的第一行有一条默认的隐式语句。super();
            子类继承了父类,获取了父类内容(属性),所以在使用父类内容之前,要先看看父类是如何对自

        己的内容进行初始化的。

           如果父类中没有定义空参数的构造函数,那么子类的构造函数必须用super明确调用父类中的

       哪个构造函数。 同时,如果子类构造函数中使用this调用了本类构造函数时,那么super就没有

       了,因为super和this都只能定义在第一行。只能有一个。

           但是可以保证的是,子类中肯定会有其他的构造函数访问父类中的构造函数。

           注意:super语句必要到定义在子类构造函数的第一行,因为父类的初始化要先完成。

               通过super初始化父类内容时,子类的成员变量并未显示初始化。等super()父类初始化完毕

            后,才进行子类初始化的显示。

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)
         

class Fu{Fu(){System.out.println("fu run");}}class Zi extends Fu{Zi(){//super();//隐含调用了父类的空参数的构造函数System.out.println("zi run");}}


4.多态

   多态指的是某一事物的多种存在形式。比如我,是一种动物,动物中的人,同时还是一名学生等。我这一对象就具有了多种形态,既具备人的形态,又具备学生的形态。这就是多态性。

多态在代码中的体现:父类或者接口指向其子类的对象。

(1)多态的好处和弊端:

        好处:提高了代码的扩展性,前期定义的内容可以使用后期的内容。

        弊端:前期定义的内容不可以调用后期的特有内容。

        

    多态的前提是:必须要有关系,即继承或者实现。还必须要有覆盖。

(2)多态—转型

可以结合代码说明:



abstract class Animal{code...}class Dog extends Animal{code...}class Cat extends Animal{code...}class AnimalDemo {public static void main(String[] args) {Animal a = new Cat();//向上转型Cat c = (Cat)a;//向下转型Animal a1 = new Dog();Cat c1 = (Cat)a1;//ClassCastException//转化异常,猫和狗不存在继承关系。}}


转型分为:

    ①向上转型。代码中的Animala = new Cat();其实就向上转型,底层做了自动类型的提升,这是猫

               对象提升为动物类型。 但是猫的特有功能将无法访问。

        作用:限制对特有功能的访问。

    ②向下转型。Catc = new Cat();

      如果你还想调用具体动物猫的特有功能,那么可将该对象进行向下转型。

      作用:可以访问子类中的特有方法。

     但是,看看这两句代码:Animal a1 = new Dog();

                                           Cat c1 = (Cat)a1;

     这两句代码是错误的,会发生转化异常。猫和狗不存在继承关系。

     简单说,狗是动物,但是狗不是猫。

    

     注意:对于转型,至始至终都是子类对象在做类型的变化。

(3)多态成员的特点:

        ①成员变量:

              编译时,看引用型变量所属类中是否有成员变量。有,编译通过;没有,编译失败。

              运行时,看引用类型所属类中是否有调用的成员变量,并运行该所属类中成员变量。

              简单说,编译运行看左边。

        ②成员函数(非静态)

             编译时,看引用型变量所属的类中是否有调用的函数。有,编译通过;没有,编译失败。

             运行时,看对象所属的类中是否有调用的函数。有,运行通过;没有,运行出现异常。

             简单说,编译看左边,运行看右边。

       ③静态函数

             编译时,看引用型变量所属类中是否有调用的静态函数。

              运行时,看引用型变量所属类中是否有调用的静态函数。

             简单说,编译运行看左边(和成员变量一样)。

 

         对于静态方法,是不需要对象的,直接用类名调用即可。

 

5.接口

    接口和类差不多,都是子类通过向上抽取而来的共性的内容。如果抽象类中没有定义非抽象的方法,只有抽象的方法时,这时,这个抽象类可以定义为接口。

   定义接口用interface关键字来实现。

 (1)接口的成员:

         常量:其固定的修饰符是publicstatic final.

        抽象方法:其固定的修饰符是public static。

        由此可知,接口中所有成员都是公共权限。

 (2)接口的特点:

         ①接口可以被多实现,也可以多继承。而且继承一个类的同时,还可以多实现。

         ②接口是对外暴露的规则。

         ③接口是程序功能的扩展。

         ④接口降低了耦合性。

 

       注:接口不可以实例化。只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实

例化。否则,这个子类就是一个抽象类。

 

6.final关键字

     1)final是一个修饰符,可以修饰类,方法,变量。
      2)final修饰的类不可以被继承。
      3)final修饰的方法不可以被覆盖。
      4)final修饰的变量是一个常量,只能赋值一次。

   其实在程序如果一个数据是固定的,那么直接使用这个数据就可以了,但是这样阅读性差,所以它该数据起个名称。而且这个变量名称的值不能变化,所以加上final固定。

写法规范:常量所有字母都大写,多个单词,中间用“_”连接。

 

7.内部类

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)内部类,其实相当于一种封装。一般用于类的设计。

 (1)内部类的特点:
         ①内部类可以直接访问外部类的成员。甚至是私有化的成员。
         ②外部类要访问内部类,必须建立内部类的对象。如图中的代码。

 (2)几点说明:

         ①为什么内部类可以直接访问外部类的成员?

            那是因为内部类持有了外部类的引用。格式:外部类名.this

         ②内部类中的成员不能使用静态,否则,内部类也要静态修饰。

            如果内部类是静态的,那么就相当于一个外部类。

         

class Outer{int num = 3;class Inner{int num = 4;void show(){int num = 5;System.out.println(num);//打印5System.out.println(this.num);//打印4System.out.println(Outer.this.num);//打印3}}void method(){new Inner().show();}}

(3)内部类-局部内部类

     内部类可以存放在局部位置上。

     内部类在局部位置上只能访问局部被final修饰的局部变量。否则局部变量生命周期短,无法访问。

且看看一下代码说明:

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)
   

class Outer{int num = 3;void method(){final int x = 9;   class Inner   {void show()    {System.out.println("show..."+num);System.out.println("show..."+x);//从内部类中访问本地变量x,x需要被声明为final            //x为局部变量,生命周期较短,出栈后,对象无法访问。}   }   Inner in = new Inner();   in.show();}}class InnerClassDemo3 {public static void main(String[] args) {new Outer().method();}}


(4)内部类-匿名内部类

     匿名内部类就是内部类的简写格式。

     简写的前提:内部类必须继承或者实现一个外部类或者接口。

     

    匿名内部类:其实就是一个匿名子类对象。

    

    其格式为:new父类or接口(){子类内容}

黑马程序员鈥斺斆嫦蚨韵螅ǘ)(单例,继承,多态,接口,final,内部类)

  

public void method(){//new Inner().show();new Demo(){     //匿名内部类void show(){System.out.println("show"+num);}}.show();        }}


 

 通常的使用场景之一:
         当函数参数是接口类型时,而且接口中的方法不超过三个(超过三个,使用匿名内部类,方

        法很多,阅读性差),可以用匿名内部类作为实际参数进行传递。