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


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);//打印5
			System.out.println(this.num);//打印4
			System.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();        
	}
}


 

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

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

 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值