黑马程序员java学习日记——面向对象(二)

------- android培训java培训、期待与您交流! ----------

一、继承(面向对象的特点之二)

1、概述:

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需在定义这些属性和行为,只要继承那个类即可。

多个类可以称为子类,单独这个类称为父类或者超类。

子类可以直接访问父类中的非私有的属性和行为。

2、怎样使用继承:

   通过extends关键字让类与类之间产生继承关系

   示例:

      class A extend B{}

3、继承的好处:

   A:提高了代码的复用性

   B:继承的出现让类与类之间产生了关系,提供了多态的前提

4、继承的特点:

   Ajava只支持单继承,不支持多继承

       例如:

 

class A
{
	void show()
	{
		System.out.println("a");
	}
}
class B
{
	void show()
	{
		System.out.println("b");
	}
}

class C extends A,B  
{
     C c = new C();
c.show();
}

这样,结果不确定。因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。

 Bjava支持多层继承(继承体系)

       class A{}

class B extends A{}

class C extends B{}

如何使用一个继承体系中的功能呢?

想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系中共性功能。

通过了解共性功能,就可以知道该体系的基本功能。

那么这个体系已经可以基本使用了。

那么在具体调用时,要创建最子类的对象,为什么呢?

一是因为有可能父类不能创建对象,

二是创建子类对象可以使用更多的功能,包括基本的也包括特有的。

简单一句话:查阅父类功能,创建子类对象使用功能。

       定义继承时需要注意的细节:

        a:不要仅为了获取其他类中的某个功能而去继承

        b:类与类之间要有所属(” is  a ”)关系。xx1xx2的一种

5、继承的成员关系:

    A:成员变量

                    在子类中使用一个变量的时候:

                           首先在局部范围内找,如果有就使用。

                           否则,在子类中找,如果有就使用。

                           否则,在父类中找,如果有就使用。

                           否则,就报错。

 

                    thissuper的区别:

            this代表本类对象的引用

            super代表父类对象的引用

                           this():表示调用本类的构造方法

                           super():表示调用父类的构造方法

 

                           this.成员变量:表示调用本类的成员变量

                           super.成员变量:表示调用父类的成员变量

 

                           this.成员方法:表示调用本类的成员方法

                           super.成员方法:表示调用父类的成员方法

 

                    最常见的用法:

                           this用于区分局部变量和成员变量

                           super用于区分子类和父类相同名称的变量

             B:成员方法

                    在子类中使用一个方法的时候:

                           首先,在子类中找,如果有就使用。

                           否则,在父类中找,如果有就使用。

                           否则,就报错。

 

                    子父类同名的方法,在java中被称为方法重写。

                           要求:方法声明相同。

                                 子类的修饰符权限要大于等于父类的权限。

                                 不能重写父类的私有方法。

                                

重写和重载的区别?

答:重写override表示子类中的方法可以与父类中的某个方法完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中定义的方法,这相当于把父类中定义的那个完全相同的方法覆盖了。

    重载overload表示同一个类中可以有多个名称相同的方法,但是参数列表各不相同。

             C:构造方法

                    在创建子类对象的时候,会去创建父类的对象。

                    因为在子类的构造方法中,默认第一条语句有一个super()

 

                    假如父类没有无参构造,那么怎么解决呢?

                           a:通过super调用父类的其他构造

                           b:通过this调用本类的其他构造。

                    一般建议把无参构造方法自己给出。

  代码示例:

 

class Fu//定义父类
{	
	int num = 10;//父类中变量
	public Fu()//父类无参构造方法
	{
		System.out.println("Fu num:"+num);
	}
	public void method()//父类中方法
	{
		System.out.println("Fu method");
	}
	public void function()//父类中function方法
	{
		System.out.println("Fu function");
	}
}
class Zi extends Fu//定义子类继承父类
{
	int num = 20;//定义子类变量
	public Zi()//子类构造方法
	{
		System.out.println("Zi num:"+num);
	}
	public void show()//子类show方法
	{
		int num = 30;
		System.out.println("num:"+num);
		System.out.println("num:"+this.num);
		System.out.println("num:"+super.num);
	}
	public void method()//子类method方法
	{
		System.out.println("Zi method");
	}
}
class ExtendsTest//测试类
{
	public static void main(String[] args)
	{
		//请按照顺序写出下列程序的运行结果。
		Zi zi = new Zi();//创建子类对象
		/*结果:
			Fu num:10
			Zi num:20
		*/
		zi.show();//调用子类show方法
		/*结果:
			num:30
			num:20
			num:10
		*/
		zi.method();//调用method方法
		/*结果
			Zi method
		*/
		zi.function();//调用function方法
	}
} 

6、函数的覆盖(override

 定义:

 当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖)

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

注意事项:

A:子类覆盖父类必须保证子类访问权限大于等于父类访问权限

B:静态只能覆盖静态

C:父类中的私有方法不可以被覆盖

D:在子类覆盖的方法中,继续使用被覆盖的方法可以通过super.函数名获取

代码示例:

class Fu
{
	private void study()
	{
		System.out.println("Fu - study");
	}

	public void show()
	{
		System.out.println("Fu - show");
	}
}

class Zi extends Fu
{
	/*
	public void study()
	{
		System.out.println("Zi - study");
	}
	*/

	public void show()//覆盖父类中的show方法
	{
		super.show();
		System.out.println("Zi - show");
	}

	public void method()
	{
		System.out.println("Zi - method");
	}
}

class ExtendsDemo3 
{
	public static void main(String[] args) 
	{
		Zi zi = new Zi();
		zi.show();
		//zi.method();
		//zi.study();
	}
}

覆盖的应用:

当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,有定义了子类特有的内容。

7、子类的实例化过程

在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式的语句 super();

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

为什么子类一定要访问父类中的构造函数?

因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问一下父类中的构造函数。

如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。

注意:super语句一定定义在子类构造函数的第一行。

这就是子类的实例化过程。

结论:

子类的所有的构造函数,默认都会访问父类中空参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super();

当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。

class Fu //extends Object
{
	int num ;
	Fu()
	{
		//super();
		num= 60;
		System.out.println("fu run");
	}
	Fu(int  x)
	{
		System.out.println("fu ...."+x);
	}
	
}

class Zi extends Fu
{
	Zi()
	{
		super();  //子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
//因为子类每一个构造函数内的第一行都有一句隐式super();
		//super(4);
		System.out.println("zi run");
	}
	Zi(int x)
	{
this();//子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
//子类中至少会有一个构造函数会访问父类中的构造函数。
//super();
		//super(3);
		System.out.println("zi..."+x);
	}
}

class  ExtendsDemo4
{
	public static void main(String[] args) 
	{
		Zi z = new Zi(0);
		System.out.println(z.num);
	}
}

8final关键字

 final是“最终”的意思,作为一个修饰符,可以修饰类、变量、函数。final修饰的类不可以被继承,为了避免被继承,被子类复写功能;final修饰的方法不可以被复写final修饰的变量是一个常量,只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。

当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。而这个值不需要改变,所以加上final修饰。作为常量,所有字母都大写,如果有多个单词组成,单词间通过_(下划线)连接。

内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。

因为当函数不被调用的时候,变量也会随之消失,为了能让内部类使用该变量,该变量就要被final修饰,成为常量,延长了变量的生命周期。

class Demo
{
	final int x = 3;
	public static final double PI = 3.14;
	final void show1()
	{}
	void show2()
	{
		final int y = 4;
		System.out.println(3.14);
	}
}
class SubDemo extends Demo
{
	//void show1(){}
}
class FinalDemo 
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}

二、多态(面向对象的特点之三)

1、定义:

    就是对象在不同时刻代表的不同状态

2、多态的前提:

    A:类与类之间有继承关系或者实现关系

    B:有方法的重写

    C:有父类引用指向子类对象

       父类的引用也可以接收自己的子类对象

  举例;

   class Fu{ public void show(){sop("Fu")} }

   class Zi extends Fu{ public void show(){sop("zi")} }

   多态:

       Fu f = new Zi();

3、多态的好处:

  A:提高了代码的后期的维护性

  B:提高了代码的后期的扩展性

4、多态的弊端:

   只能使用父类中定义过的方法,子类特有方法不能使用

abstract class Animal
{
	abstract void eat();
}
class Cat extends Animal
{
	public void eat()
	{
		System.out.println("吃鱼");
	}
	public void catchMouse()
	{
		System.out.println("抓老鼠");
	}
}
class Dog extends Animal
{
	public void eat()
	{
		System.out.println("吃骨头");
	}
	public void kanJia()
	{
		System.out.println("看家");
	}
}
class Pig extends Animal
{
	public void eat()
	{
		System.out.println("饲料");
	}
	public void gongDi()
	{
		System.out.println("拱地");
	}
}
//-----------------------------------------
class DuoTaiDemo2 
{
	public static void main(String[] args) 
	{
		//Animal a = new Cat();//类型提升。 向上转型。
		//a.eat();
		//如果想要调用猫的特有方法时,如何操作?
		//强制将父类的引用。转成子类类型。向下转型。
		///Cat c = (Cat)a;
		//c.catchMouse();
		//千万不要出现这样的操作,就是将父类对象转成子类类型。
		//我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
		//多态自始至终都是子类对象在做着变化。
//		Animal a = new Animal();
//		Cat c = (Cat)a;
		/*
		毕姥爷 x = new 毕老师();
		x.讲课();
		毕老师 y = (毕老师)x;
		y.看电影();
		*/
		function(new Dog());
		function(new Cat());
	}
	public static void function(Animal a)//Animal a = new Cat();
	{
		a.eat();
		/*
		if(a instanceof Animal)
		{
			System.out.println("haha");
		}
		else 
		*/
		if(a instanceof Cat)
		{
			Cat c = (Cat)a;
			c.catchMouse();
		}
		else if(a instanceof Dog)
		{
			Dog c = (Dog)a;
			c.kanJia();
		}
		/*
		instanceof : 用于判断对象的类型。 对象 intanceof 类型(类类型 接口类型)  
		*/
	}
}

多态的测试:

              向上转型:是为了多个对象使用同一个引用调用。

              向下转型:是为了对象使用自己的特殊方法。

5在多态中非静态成员函数的特点:

在编译时期:看引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有,编译失败;在运行时期:看对象所属的类中是否有调用的方法。

简单总结:成员函数在多态调用时,边一看左边,运行看右边。

在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)

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

无论编译和运行,都参考左边

class Fu
{
	static int num = 5;
	void method1()
	{
		System.out.println("fu method_1");
	}
	void method2()
	{
		System.out.println("fu method_2");
	}
	static void method4()
	{
		System.out.println("fu method_4");
	}
}
class Zi extends Fu
{
	static int num = 8;
	void method1()
	{
		System.out.println("zi method_1");
	}
	void method3()
	{
		System.out.println("zi method_3");
	}

	static void method4()
	{
		System.out.println("zi method_4");
	}
}
class  DuoTaiDemo4
{
	public static void main(String[] args) 
	{
		
//		Fu f = new Zi();
//
//		System.out.println(f.num);
//
//		Zi z = new Zi();
//		System.out.println(z.num);
		//f.method1();
		//f.method2();
		//f.method3();//编译失败,因为父类中没有方法method3

		Fu f = new Zi();
		System.out.println(f.num);
		f.method4();
		Zi z = new Zi();
		z.method4();

//		Zi z = new Zi();
//		z.method1();
//		z.method2();
//		z.method3();
	}
}	







 


 

 

你可能感兴趣的:(java基础学习)