继承的概念和实现 、 super关键字 、 Object常见方法、抽象类、接口、模板方法模式、成员内部类、匿名内部类

本文探讨了Java中的继承概念,super关键字的应用,方法重写,Object类常见方法,以及抽象类、接口、内部类和匿名内部类。通过实例演示,展示了如何利用继承进行代码复用和层次设计,以及多态在实际场景中的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇博客将会涉及到:

  • 继承的概念和实现
  • super关键字
  • 方法重写—Override
  • Object常见方法

继承的概念:

生活中,继承的概念随处可见,继承需要符合的关系:is-a;父类更通用、子类更特殊更具体。就比如说:动物是一个类,那么它的子类可以是:食草动物、食肉动物。

  • 对于java语言来说,继承背后的思想就是基于已存在的类来构建新类,当从已存在类继承时,就重用了它的方法和属性,还可以添加新的方法和属性来定制新类以应付需求。约定: 从其他类导出的类叫做子类,被导出的类叫做父类。在java中,除了Object类之外,所有类都是子类,都只有唯一父类。就是在创建类的时候,如果不写类继承自哪一个类,系统会默认的认为是Object的子类,通过下图方法可查看,一个类继承的父类:
    在这里插入图片描述
  • 继承在OOP中不可或缺(不写继承自哪一个类会默认继承Object类),创建一个类时总是在继承,继承的意义: 代码重用、体现不同的抽象层次。父子类关系: 父类更抽象,更一般、子类更具体,更特殊。
  • 在java语言中,用extends 关键字来表示一个类继承了另外一个类,如下:
public class Teacher extends Person{
}
  • extends使用示例:
package fhn.demo.java;
class Person{
	String name;
	String address;
	public void eat(){
		System.out.println("人吃饭");
	}
	public void drink(){
		System.out.println("人喝水");
	}
}
class Student extends Person{
	String address;
	float score;
	void goToSchool(){
		System.out.println("去上学");
	}
}
public class Test {
	public static void main(String[] args) {
		Person p=new Person();
		Student s=new Student();
		
		p.name="人";
		p.eat();
		p.drink();
		
		s.name="学生";
		s.eat();
		s.drink();
		s.goToSchool();
	}
}

super关键字:

super关键字的特点:

  • super和this关键字的特点类似;super代表的是父类对象的引用
  • 当子父类的成员出现同名时,可以通过super来区分
  • 子类构造方法中,通过super关键字调用父类的构造方法
  • 在子类构造方法中默认都是调用了父类的构造方法super()这个是无参数的,当想调用父类的构造方法是有参数的时候就要自己在子类的第一行输入super(参数)来调用父类的构造方法。
  • 强调: 当构造一个子类对象的时候一定会先调用父类的构造方法来初始化父类的字段。调用父类构造方法的语句必须是子类构造方法中的第一条指令。
  • 注意: 子类只能调用父类的构造方法来初始化参数,当然也可以在自己的构造方法中添加一些父类构造方法没有的语句
  • java继承之私有权限:父类的私有属性和私有方法不会被子类继承,但是可以通过父类的公有方法来间接访问父类的私有属性
class Person{
	String name;
	String address;
	//public Person(){};//无参构造方法,当不写带参数的构造方法,系统会默认的添加无参构造方法
	public Person(String name,String adress) {//父类的构造方法
		this.name=name;
		this.address=adress;
		System.out.println("父类构造方法被调用");
	}
	public void eat(){
		System.out.println("父类的人吃饭");
	}
	public void drink(){
		System.out.println("父类的人喝水");
	}
}
class Student extends Person{
	float score;
	public Student(String name,String adress) {//子类的构造方法
		super(name,adress);//在子类的构造方法里面通过super调用父类的构造方法
						   //调用父类构造方法的语句必须是子类构造方法中的第一条指令。
		/*
		 * this.name=name;
		 * this.adress=adress;//这种写法不可以,当父类里面存在无参构造方法时
		 * 					  //子类需要通过super关键字来调用父类的构造方法在自己的构造方法里面进行参数的初始化
		 * */
		System.out.println("子类构造方法被调用");//当然也可以在自己的构造方法中添加一些父类构造方法没有的语句
	}
	void goToSchool(){
		System.out.println("去上学");
	}
	public void eat(){
		super.eat();//当子父类的成员出现同名时,可以通过super来区分
		System.out.println("子类的人吃饭");
	}
}
public class Main {
	public static void main(String[] args) {
		Person p=new Person("你们","北京");
		Student s=new Student("我们","河北");//当构造一个子类对象的时候一定会先调用父类的构造方法来初始化父类的字段
		p.eat();
		p.drink();
		
		s.eat();
		s.drink();
		s.goToSchool();
	}
}

Object常见方法:

  • java中,所有的类都可以直接或间接继承自java.lang.Object类,可以说Object是java中所有类的祖先即根类。
  • java任何类中都继承了Object类中的方法,主要有:toString()equals()hashcode()clone()getClass()finalize()
  • String toString(): 返回该对象的字符串描述信息。默认输出格式是:类名[字段值,字段值…]。只要对象与一个字符串通过“+”连接,系统就会自动调用toString获得对象的字符串描述符。常被改写:可以根据用户的需求对其进行重写。
  • Boolean equals(): OBject类原始功能是实现判断两个对象是否具有相同的引用,要求判断两个对象状态的相等性。
class Person{
	String name;
	String address;
	//public Person(){};//无参构造方法,当不写带参数的构造方法,系统会默认的添加无参构造方法
	public Person(String name,String adress) {//父类的构造方法
		this.name=name;
		this.address=adress;
		System.out.println("父类构造方法被调用");
	}
	public String toString() {//在子类里面对Object类父类toString方法进行重写
		//默认返回父亲的toString,return super.toString();
		return "person message:"+name+address;
	}
	public boolean equals(Object arg0) {//对equals进行重写,判断两个类里面的内容知否一致
		// TODO Auto-generated method stub
		//return super.equals(arg0);
		Person p=(Person) arg0;
		if(this.name==p.name&&this.address==p.address)//java中可用==表示两个字符串是否相等,在C语言中用strcmp
			return true;
		else
			return false;
	}
}
public class Main {
	public static void main(String[] args) {
		Person p=new Person("你们","北京");
		/*不对toString方法进行重写
		 * System.out.println(p.toString());//输出:Person@659e0bfd----Person类名、@659e0bfd是类的内存地址
										//若果有包名,还会将包名打印出来
										//默认打印这个对象的地址和相关信息,返回值是字符串类型
		*/
		
		//对toSting方法进行重写
		System.out.println(p.toString());//输出--你们北京
		
		Person p2=new Person("你们","北京");
		/*
		 * 不对equals进行重写
		System.out.println(p2.equals(p));返回的是Boolean类型的值,比较的是两个对象的地址值
										 不是比较两个类的内容是否一致
		*/
		//方法重写后输出:
		System.out.println(p2.equals(p));//重写方法后,比较的是两个对象的内容是否一致
	}
}

继承学习综合练习:

class Wapon
{
	String name;
	void WaponAttack()
	{
		System.out.println("武器攻击");		
	}

}
class K98 extends Wapon
{
	void WaponAttack()//重写父类方法
	{
		System.out.println("98K攻击");
		System.out.println("一击毙命");
	}
}
class Dao extends Wapon
{
	void WaponAttack()//重写父类方法
	{
		System.out.println("砍刀攻击");
		System.out.println("刀刀见血");
	}
}
class Play
{
	String name;
	String level;
	Wapon wapon;
	int id;
	void attack()
	{
		System.out.println("玩家攻击");
		wapon.WaponAttack();
	}
}
public class Main {
	public static void main(String[] args) {
		Play p1=new Play();
		p1.name="玩家一";
		p1.level="青铜";
		//p1.wapon =new Wapon();
		
		p1.wapon =new Dao();//多态
		p1.attack();//如果直接写这句话,会出现空指针异常,要先给wapon赋值再使用
		System.out.println();
		p1.wapon =new K98();//多态
		p1.attack();//如果直接写这句话,会出现空指针异常,要先给wapon赋值再使用
	}
}

java继承的简单工厂模式:

  • 工厂模式之前在写智能家居的代码的时候用C语言加链表实现过,在用C语言实现时,就是构建了连个链表分别代表指令工厂和控制工厂,然后将设备通过添加节点的方式插入到对应的链表,在使用的时候,通过设备或者指令名称进行查找然后调用相关的函数,实现起来比较繁琐。
  • 而在java中有了继承的概念,就可以将那些结点看作是继承自一个父类的子类,然后构建一个查找的类对所需要的内容进行查找即可,查找到返回查找的对象的引用,然后就可以调用相关的方法。实现起来比较简单。
class Fruit   //相当于之前用C语言写的链表的头部
{
	String name;
	void grow()
	{
		System.out.println("野蛮生长的水果");		
	}
	public Fruit(String name)
	{
		this.name=name;		
	}
}
class Apple extends Fruit
{
	public Apple(String name){
		super(name);
	}
	void grow()//对父类方法进行重写
	{
		System.out.println("野蛮生长的"+name);
	}
}
class Peach extends Fruit
{
	public Peach(String name){//构造方法调用父类的构造方法
		super(name);
	}
	void grow()//对父类方法进行重写
	{
		System.out.println("野蛮生长的"+name);
	}
}
class Factory   //在这个类里面进行对水果的查找
{
	public static Fruit getFruit(String name)
	{
		if(name=="苹果")
			return new Apple(name);//这里有用到多态
		else if(name=="桃")
			return new Peach(name);
		else{
			return null;
		}
	}
}
public class Main {
	public static void main(String[] args) {
		if(Factory.getFruit("苹果")!=null){
			System.out.println("找到了苹果");
			Factory.getFruit("苹果").grow();
		}
		if(Factory.getFruit("桃")!=null){
			System.out.println("找到了桃");
			Factory.getFruit("桃").grow();
		}
		if(Factory.getFruit("葡萄")==null){
			System.out.println("没有该水果");
		}
	}
}

抽象类:

Java中可以定义没有方法体的方法,该方法由子类来具体实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。

  • 抽象方法的特点: 只有方法头没有方法体的方法称为抽象方法。 抽象方法用abstract来修饰。 抽象方法代表一种不确定的操作或者行为。 抽象方法不能被调用。 抽象类代表一种抽象的对象类型。 抽象类不能实例化 抽象类中可以有具体方法,可以没有抽象方法。
abstract class Demo1
{
	abstract public void method();//抽象方法只能放在抽象类里面,在这里声明抽象方法就要将类声明为抽象类
}
class Demo2 extends Demo1 //抽象类使用的时候一般是使用新的类继承抽象类,然后重写里面的抽象方法
{
	public void method()
	{
		System.out.println("Demo2重写的Demo1的方法");
	}
}
public class Main {
	public static void main(String[] args) {
		/*
		 * 抽象类在使用的时候不能实例化
		 * 添加函数体则如下所示,对里面的抽象方法进行补充,这种方式算不上实例化,是做的一个匿名的内部类
		 * Demo1 d=new Demo1(){
			public void method() {
			
			}
		 };
		 */
		Demo2 d=new Demo2();
		d.method();
	}
}

模板方法模式(也是抽象类的一种使用方法):

定义: 一个模板方法用一些抽象的操作定义一个算法,而子类将重定义这些操作以提供具体行为。
意图: 定义了一个操作中的一个算法框架,把一些步骤推迟到子类去实现,模板方法让子类不需要改变算法结构。

具体的代码示例:

abstract class Contrl  //这个控制类只是做一个模板放到这里,因为每一个抽象方法实现不一样
{
	abstract void initUsart();
	abstract void getComand();
	abstract void openCure();
	abstract void openLight();
	abstract void OpenTv();
	public void work()  //这个方法里面是一系列的控制流程里面是抽象方法
	{
		initUsart();
		getComand();
		openCure();
		openLight();
		OpenTv();
	}
}
class STM32contrl extends Contrl  //继承自contrl这个类然后会让我们实现父类这个抽象类的所有抽象方法
{
	void OpenTv() {
		// TODO Auto-generated method stub
		System.out.println("STM32 OpenTv");
	}
	void getComand() {
		// TODO Auto-generated method stub
		System.out.println("STM32 getComand");
	}
	void initUsart() {
		// TODO Auto-generated method stub
		System.out.println("STM32 initUsart");
	}
	void openCure() {
		// TODO Auto-generated method stub
		System.out.println("STM32 openCure");
	}
	void openLight() {
		// TODO Auto-generated method stub
		System.out.println("STM32 openLight");
	}
}
class C51contrl extends Contrl  //继承自contrl这个类然后会让我们实现父类这个抽象类的所有抽象方法
{
	void OpenTv() {
		// TODO Auto-generated method stub
		System.out.println("C51 OpenTv");
	}
	void getComand() {
		// TODO Auto-generated method stub
		System.out.println("C51 getComand");
	}
	void initUsart() {
		// TODO Auto-generated method stub
		System.out.println("C51 initUsart");
	}
	void openCure() {
		// TODO Auto-generated method stub
		System.out.println("C51 openCure");
	}
	void openLight() {
		// TODO Auto-generated method stub
		System.out.println("C51 openLight");
	}
}
public class Main {
	public static void main(String[] args) {
		STM32contrl stm32=new STM32contrl();
		stm32.work();//STM32contrl这个类也继承了Contrl的work方法,该方法是总的控制流程
		C51contrl c51=new C51contrl();
		c51.work();
	}
}

接口的概念和作用:

接口语法:interface 接口{ //公有静态方法、抽象方法 }

接口的特点: 接口中只能存放静态常量和抽象方法 java接口是对功能的拓展 通过实现接口,java类可以实现多实现 一个类可以同时继承(extends)一个父类并且实现(implement)多个接口 接口与接口之间可以使用extends实现继承。

接口与抽象类的区别:

  • 抽象类和具体实现之间是一个继承关系,也就是如果采用抽象类的方式,则父类和子类在概念上应该是相同的。
  • 接口和实现类在概念上不要求相同,接口只是抽取相互之间没有关系的类的共同特征,而不去关注类之间的关系,它可以使没有层次关系的类具有相同的行为。
  • 抽象类是对一组具有相同属性和行为的逻辑上上有关系的事物的一种抽象,而接口则是对一组具有相同属性和行为的逻辑上不相关的事物的一种抽象。

interface Move
{
	abstract void eat();
	abstract void drink();
}
class man implements Move
{
	public void eat() {
		System.out.println("人类吃");		
	}
	public void drink() {
		System.out.println("人类喝");		
	}
}
class animal implements Move 
{
	public void eat() {
		System.out.println("动物吃");	
	}
	public void drink() {
		System.out.println("动物喝");		
	}
}
public class Main {
	public static void main(String[] args) {
		new man().drink();
		new animal().eat();	
	}
}

内部类:

  • 概念: 所谓的内部类(Inner Class),顾名思义,就是将一个类定义在另一个类的内部,内部的类称之为内部类。
  • 特点: 内部类可以很好的实现隐藏,可以使用protected、private修饰符。 内部类可以直接访问外部类所有成员包括私有成员。 外部类不能直接访问内部类的成员,必须首先建立内部类对象才能访问。
  • 成员内部类及应用: 成员内部类属于外部类的实例成员,成员内部类可以有public、private、default、protected权限修饰符。在成员内部类中访问外部类的成员方法和属性,要使用“外部类名.this.成员方法”和“外部类名.this.成员属性”的形式 。 创建成员内部类的实例使用“外部类名.内部类名 实例=外部类实例名.new 内部类 构造方法(参数)”的形式。
  • 成员内部类有以下限制: 成员内部类不能与外部类重名 不能在成员内部类中定义static属性,方法和类(static、final形式的常量定义除外),因为一个成员内部类实例必然与一个外部类实例关联,static成员完全可以移到其外部类中去。
  • 在一个java文件中只能有一个public类,如果有多个就要放在其他文件中
class Outer
{
	int data;
	public Outer(int data) {
		this.data=data;
	}
	void printfData()
	{
		System.out.println("外部类打印外部类data:"+data);
	}
	class Inner{
		int data;
		public Inner(int data) {
			this.data=data;
		}
		void printfData()
		{
			System.out.println("内部类打印外部类的data:"+Outer.this.data);
			System.out.println("内部类打印内部类的data:"+data);
		}
		void printouter()
		{
			System.out.println("内部类调用外部类方法打印data如下:");
			Outer.this.printfData();
		}
	}
}
public class Main {
	public static void main(String[] args) {
		// 创建成员内部类的实例使用 外部类名.内部类名 实例=外部类实例名.new 内部类 构造方法(参数)的形式。
		Outer Out1=new Outer(10);//创建成员内部类的实例得先创建外部类的实例
		Outer.Inner In1=Out1.new Inner(20);
		Out1.printfData();
		In1.printfData();
		In1.printouter();
	}
}

匿名内部类及应用:

  • 内部匿名类: 一个带具体实现的父类或者父接口的匿名的子类对象。
  • 匿名内部类的特点: 匿名内部类是没有名称的内部类,没办法引用他们。必须在创建时,作为new语句的一部分来声明并创建他们的实例。 匿名内部类必须继承一个类(抽象的、非抽象的都可以)或者实现一个接口,所有的父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象的方法。
  • 语法: 实例一个匿名内部类----> new interface/superclass(){类体}这形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口,并同时创建该匿名类的一个新实例。
abstract class Demo
{
	abstract void printfInfo();
	abstract void interPrintf();//在接口中默认是抽象方法
}
interface Demo2
{
	void interPrintf();//在接口中默认是抽象方法
}
public class Main {
	public static void main(String[] args) {
		new Demo(){
			void printfInfo() {
				System.out.println("这不是demo类的实例化,而是匿名内部类的方法");
			}
			void interPrintf() {
				System.out.println("所有的父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象的方法");
			}
		}.printfInfo();
		
//		Demo d=new Demo(){这种形式是以多态的形式创建匿名内部类,new Demo()是Demo 的子类的对象,在这里用父类引用来接收的
//			void printfInfo() {
//				System.out.println("这不是demo类的实例化,而是匿名内部类的方法");
//			}
//			void interPrintf() {
//				System.out.println("所有的父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象的方法");
//			}
//		};
//		d.interPrintf();
//		d.printfInfo();
		
		new Demo2(){
			public void interPrintf() {
				System.out.println("这不是接口的实例,而是匿名内部类的方法");				
			}
		}.interPrintf();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值