黑马程序员---Java基础---面向对象:继承、抽象类、接口

-------  android培训 java培训 、期待与您交流! ----------
面向对象:继承、抽象类、接口
一、继承
1.定义
多类中存在相同属性和行为时,将这些内容抽取到一个单独类中,那么多个类无需再定义这些属性和行为,只需继承单独的那个类即可。其中的多个类称为子类,单独的这个类称为父类或超类。
继承即为一个类和另一个类之间的继承关系。而父类的出现是由子类一级一级的抽取而获得的,即父类是子类的共性内容。
2.继承的好处
(1)提供了代码的复用性;
(2)让类与类之间产生了关系,为面向对象的特点多态提供了前提。
3.继承的注意事项
(1)继承不支持多继承,只继承单继承,但支持多层继承。因为若一个类可以同时继承多个父类
则当父类之间出现了相同功能时,子类使用时会不知道该调用哪一个功能。所以java不支持多继承
但java保留这种机制,并用另一种体现形式--多实现来完成。
(2) 千万不要为了获取其他类的功能,简化代码而继承,必须是类与类之间有所属关系才可以继承。

4.继承的特点
(1)继承用到的关键字为extends
(2)对于一个继承体系的使用,是查阅父类中的方法,而创建最底层子类的对象。
5.继承中类的成员变量和成员函数的特点
(1)成员变量
当父类和子类中有同名的成员变量的定义时,则当子类对象调用时,默认使用的是子类中的成员变量。
要想使用父类的成员变量,则在使用变量的前面加上super。

例子:

class Animal
{
	int num=4;
}
class Dog extends Animal
{
	int num=5;
	void show()
       {
		System.out.println(num);//此时结果为5,因为默认的是this.num
		System.out.println(super.num);//结果为4,即调用的是父类中的变量。
	}
}
class Test
{
	public static void main(String[] args) 
	{
		Dog dog=new Dog();
		dog.show();
	}
}
(2)super
this:表示本类对象,代表的是调用它所在的函数的本类对象。
super:表示的是父类的引用。
当子父类出现同名成员时,可以用super区分。

子类要调用父类构造函数时,可以用super语句。

例子:

class Animal
{
	String name;
	Animal(String name)
	{
		this.name = name;
	}
}
class Dog extends Animal
{
	Dog(String name)
	{
		super(name);//调用父类构造函数
	}
}
(3)成员函数
子类可以直接继承父类中的函数,也可以根据自己的情况将父类中具有的功能主体自己再重新
写一次,即出现了子父类间函数的覆盖现象。
6.函数覆盖

子类中出现与父类中一模一样的方法时,会出现覆盖操作,也成为重写或复写。

(1)覆盖的特点
1> 父类和子类中功能的定义一样,但是功能主体不一样。
2> 当子类对象调用该功能时,会运行子类中的此功能,如同父类的函数被覆盖一样。

3> 在子类覆盖方法中,若想使用父类被覆盖的方法,可以通过super.函数名来获取。
(2)子类函数覆盖父类函数的条件
1> 子类函数的权限必须大于等于父类函数的权限。

2> 父类中的私有方法和被final修饰的方法不可以被覆盖
3>  静态只能覆盖静态。
(3)由覆盖而产生的思想
当子类需要父类的功能,而功能主体中有子类特有的属性,可以复写父类的功能,这样沿袭了父类功能,又定义了子类特有内容。

(4)函数覆盖和函数重写的区别

函数重载:在同一个类中,存在多个同名函数,通过它们的参数列表(参数类型、参数个数、参数顺序)的不同来区分。

函数覆盖:在子类中出现和父类(函数名、参数列表、返回值类型)一模一样的函数

例子:

class Tel
{
	void show()
	{
		System.out.println("number");
	}
}
class NewTel extends Tel
{
	void show()//复写了父类的相同功能
	{
		super.show();//调用父类的原有功能
		System.out.println("name");//增加新的功能
		System.out.println("pic");	
	}
}
class MethodTest
{
	public static void main(String[] args)
	{
		NewTel nt=new NewTel();
		nt.show();
	}
}

7.继承中的构造函数特点

(1)构造函数之间无覆盖功能。但是子类的构造函数会调用父类的构造函数,利用super语句子类构造函数之间也可以调用,通过this语句。

(2)子类的构造函数中至少有一个构造函数默认的第一行有一条隐式的语句super(),来调用父类的构造函数。
例子:

class Animal
{
	<pre name="code" class="java">        Animal<span style="font-family: Arial, Helvetica, sans-serif;">()</span>
{System.out.println("Animal-----run");}}class Dog extends Animal{Dog(){//默认有super()System.out.println("Dog--run");}Dog(int num){this();//当子类构造函数的首句是this()语句时,则就没有默认的super()语句了System.out.println("Dog-----------num");}}class ConstructorTest {public static void main(String[] args) {Dog dog=new Dog();//最终结果为Animal-----run // Dog--run}}</span>
 
 (3)当父类中无空参数的构造函数时,则子类中必须手写上一句super(参数)语句,与父类中的构造函数一样,参数填父类构造函数参数的类型的值。 
 
例子:

class Animal
{
	Animal(int x)
	{
		System.out.println("Animal-----x");
	}
}
class Dog extends Animal
{
	Dog()
	{
		//由于父类无无参的构造函数,所以此处手冻的写上
		super(3);
		System.out.println("Zi--run");
	}
	Dog(int num)
	{
		this();//当子类构造函数的首句是this()语句时,则就没有默认的super()语句了
		System.out.println("Zi-----------num");
	}
}
class ConstructorTest 
{
	public static void main(String[] args) 
	{
		Dog dog=new Dog();//最终结果为Animal-----3
			      //          Dog--run
		Dog dog1=new Dog(4);//结果为Animal-----3
				//结果为Dog----------4
				
	}
}</span>

(4)为什么子类的构造函数的首句一定要访问父类的构造函数的呢?
因为父类中的数据子类是需要继承的,那么子类在创建对象并对对象进行初始化时,应该先要看看父类中是怎么对数据进行初始化的。所以子类的构造函数的首句要访问父类的构造函数。

(5)总结
1> 类的所有的构造函数,默认都会访问父类中空参数的构造函数,因为子类每一个构造函数的首句都有一句隐式的super()语句。
2> 当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。
3> 当然,子类中的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。但是子类中至少有一个构造函数会访问父类中的构造函数。


二、抽象类

1.定义

多个对象都具备相同的功能,但是功能的具体内容不同,在向上抽取的过程中,只抽取功能定义,并未抽取功能内容。只有功能声明,没有功能主体的方法称为抽象方法。包含抽象方法的类就是抽象类。

2.抽象类的特点

1> 抽象类和抽象方法必须用abstract关键字修饰。

2> 抽象方法只有方法声明,没有方法体,定义在抽象类中。

3> 抽象类不可以实例化。

4> 抽象类通过其子类实例化。子类必须覆盖抽象类中的所有抽象方法才可以实例化对象,不然该子类也是抽象类。

5> 抽象类中可以有抽象方法,也可以没有,那么此抽象类只是为了不让创建它的对象。

3.抽象类和一般类的区别
抽象类和一般类没有太大区别,该怎么描述事物就怎么描述事物,只不过该事物出现了一些
看不懂的东西,这些不确定的部分,也是该事物的功能,需要明确出现,但是无法定主体,所以
通过抽象方法来表示。
4.由抽象类而总结出的编程思想:模板方法设计模式
在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,
那么这时就将不确定的部分暴露出来,定义为抽象的,由该类的子类去完成。

例子:

/**
需求:获取一段程序的运行时间。
步骤:
1.定义一个获取时间的类
2.类中定义一个函数,用来获取时间
3.用一个函数单独用来记录运行的程序

模板方法设计模式:
定义:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,
      而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露
	  出来(即抽象化),由该类的子类去完成(即在子类中将此方法进行复写)。
*/
abstract class GetTime 
{
	public void getTime()
	{
		long start=System.currentTimeMillis();
		runCode();
		long end=System.currentTimeMillis();
		System.out.println("time="+(end-start));
	}
	//由于此程序并不确定,所以抽象出来
	public abstract void runCode();	
}
//此抽象方法由子类来具体实现
class SubTime extends GetTime
{
	public void runCode()
	{
		for (int x=0;x<400 ;x++ )
		{
			if (x%2==0)
			{
				System.out.println(x);
			}
			
		}
		
	}
}
class GetTimeDemo
{
	public static void main(String[] args) 
	{
		SubTime st=new SubTime();
		st.getTime();
	}
}
三、接口
1.格式

interface 接口名

{}

2.接口中的成员修饰符是固定的

成员变量:public static final 

成员函数:public abstract 

注意

接口中的成员都是public的

3.接口的特点

1> 接口是对外暴露的规则,是功能的扩展。

2> 接口可以用来多实现,即一个类可以实现多个接口。

3> 类和接口之间是实现关系,一个类可以继承一个类,并实现多个接口。

4> 接口和接口之间可以有继承关系,并且支持多继承。

5> 接口不可以创建对象,实现了接口的子类,必须覆盖接口中的所有方法才可以创建对象,否则该子类是抽象类。

6> 类实现接口用implements关键字。

例子:

interface A
{
	public abstract void methodA();
}
interface B
{
	public abstract void methodB();
}
class C
{
	protected void methodC()
	{
		
	}
}
class D extends C implements A,B //实现多个接口时,中间用逗号隔开
{
	@Override
	public void methodA()  //覆盖接口A中的方法
	{
	}
	@Override
	public void methodB()  //覆盖接口B中的方法
	{
	}
}

四、单例设计模式

1.单例设计模式

解决一个类在内存中只存在一个对象。

2.想要保证对象唯一

(1)为了避免其他程序过多的建立该类对象,先进制其他程序建立该类对象

(2)为了让其他程序访问到该类对象,只好在本类中定义一个对象

(3)为了方便其他程序对该对象的访问,可以对外提供一些访问方式

3.代码体现

(1)将构造函数私有化

(2)在类中创建一个本类对象

(3)提供一个获取到该对象的方法

4.饿汉式和懒汉式

//先初始化对象,称为饿汉式,开发会经常用饿汉式 ,因为安全
class Single
{
	private static Single s = new Single();
	private Single(){};
	public static Single getInstance()
	{
		return s;
	}
}
//需要时再初始化对象,称为懒汉式
//Single1进内存,对象还没有存在,只有调用了getInstance方法时,才会创建对象
//也称为对象的延时加载
class Single1
{
	private static Single1 s1 = null;
	private Single1(){};
	public static Single1 getInstance()
	{
		if(s1 == null)
			s1 = new Single1();
		return s1;
	}
}
//安全的懒汉式,同步代码块
class Single2
{
	private static Single2 s2 = null;
	private Single2(){};
	public static Single2 getInstance()
	{
		if(s2 == null)
		{
			synchronized (Single2.class)
			{
				if(s2 == null)
					s2 = new Single2();
			}
		}
			
		return s2;
	}
}


 






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值