一起来学习系列:JAVA——抽象类、接口、内部类与匿名内部类

抽象类

在java开发过程中存在不能拥有具体对象的类,这些类同性时可以作为其余类的父类,因为可以代表多个类,所以如果可以创建对象,那么创建对象的类别很难划分,这个时候就需要使用抽象类关键字abstract进行修饰,将使用abstract修饰的类称之为抽象类,同理。使用abstract修饰的方法称之为抽象方法

抽象类与抽象方法的特点

1、 抽象方法没有方法体连{}都没有

抽象方法就是不知道怎么实现的方法,但是我们可以书写除方法体外的代码,所以抽象方法将方法体省略其余正常书写,由子类进行方法体的完善

//宠物类
public abstract class Pet {
    
    
	public String name = "无名氏";   // 宠物昵称
	public Pet(String name){
    
    
		this.name=name;
	}
	public abstract void eat();
}

2、子类继承后抽象方法必须实现

在正常类中方法体已被书写,如果子类没有重写方法体,那么默认调用父类方法,但是在抽象方法中没有方法体,这个方法可以理解为未完成的方法,类似于声明后未赋值的变量,所以不能使用

//老鼠类
public class Mouse extends Pet{
    
    
	public Mouse(String name) {
    
    
		super(name);
	}
	@Override
	public void eat() {
    
    
		 System.out.println("老鼠"+name+"吃大米");
	}
}

3、一个类中如果存在抽象方法那么这个类一定是抽象类

4、抽象类不一定有抽象方法

5、抽象类不能创建对象但是可以声明变量

所有的类都有构造方法,如果没有显式的定义,系统会为其默认添加无参构造方法,但是被abstract修饰的类可以理解为进行了限制,不能由开发者手动调用new的方式进行构造方法的使用,但是如果子类可以通过super(参数)的方式进行调用

接口

接口在Java中是最重要的概念之一,它可以被理解为一种特殊的类,是由全局常量和公共的抽象方法所组成。
需要注意的是,在接口中的抽象方法必须定义为public访问权限,这是不可更改的。

接口其实本质上已经不是类了

接口的特点

1、接口不可以被实例化,不能有构造方法。

接口不是一个类

2、接口中的所有成员变量都是public static final

接口不是类所以不能书写类似继承的属性

3、接口中的方法都是抽象方法,接口中的方法会自动使用public abstract修饰。

在接口中不能写方法体,但是声明方法时可以直接使用 返回值类型 方法名(参数列表);的形式

4、一个类可以同时实现多个接口。

接口不是类无需遵循类的单继承而且接口使用的是实现implements 所以不是继承

5、实现类必须实现接口中的所有方法。

如果实现类中存在没有实现的方法那么这个类应为抽象类,不能被使用

6、接口可以继承接口(接口可以继承多个接口)

接口不是类所以无需遵循java中类的单继承

7、接口中不能出现静态方法,因为absctrant 不能修饰static static的方法是不能被继承的

虽然说接口的实现类是以实现方式重写方法,但是其实本质还是由接口继承抽象方法并重写,所以遵循static修饰的方法不能被继承的原则,但由于实现类必须实现接口中所有抽象方法,所以不允许使用static

//接口
public interface BossWork {
    
    
	//接口中只能书写全局静态常量与静态方法
	//所有方法默认使用 public abstract进行修饰(如果没写会默认添加)
	public void one();
	abstract void two();
	void three();
	public abstract void four();
	
	//接口可以理解为老板安排的工作
}
//另一个接口
public interface BossWork2 {
    
    
	void add();
}
//接口的实现
//通过implements关键字将接口进行关联
//接口不是类所以可以多实现
public  class My implements BossWork,BossWork2{
    
    
//实现类可以被使用的情况
	//1、实现了所有接口的抽象方法
	//2、将实现类当做抽象类创建子类继承重写所有抽象方法
	@Override
	public void one() {
    
    }
	@Override
	public void two() {
    
    }
	@Override
	public void three() {
    
    }
	@Override
	public void four() {
    
    }
	@Override
	public void add() {
    
    }
}
//接口不是类所以可以多继承
//现在BossAllWork这个接口拥有BossWork,BossWork2这两个接口中所有抽象方法
public interface BossAllWork extends BossWork,BossWork2{
    
    
}

接口与抽象类在实际开发过程中都由程序员进行编写

接口的作用

1、在程序开发初期对程序需要书写的功能做一个全面的定义

2、便于开发与维护

当程序书写完毕,进行维护时,可以通过接口快速了解相应类具体功能

抽象类与接口的区别

相同:

1、都可以书写抽象方法

2、都不能通过new关键字创建对象,都可以用来声明对象

不同:

1、抽象类既可以书写抽象方法也可以书写普通方法

2、抽象类可以书写任意属性,接口中只能书写全局静态常量

3、抽象类中可以定义构造方法(系统会默认添加无参构造方法),接口中不能定义构造方法(系统不会添加无参构造方法)

4、抽象类使用子类继承重写的方式实现抽象方法,拘泥于java类的单继承,接口使用实现类实现的方式不是类的继承所以可以多实现,接口不是类,所以接口与接口之间可以多继承

内部类

概念

在一个类中书写另一个类

分类

同级类(严格意义上来讲只是一种书写形式不是内部类)

成员内部类(全局内部类)

局部内部类(包含匿名内部类)

①同级类

在当前类同级下继续书写其他类,书写语法与普通类相同,但修饰符只能使用默认

在使用时与普通类一致,只是访问范围只有本包下,将相当于少创建了一个文件

//员工类
public abstract class Employee {
    
    
	public String name;// 姓名
	public int birthdayMonth;// 生日月份
	public double salary;// 薪资

	public abstract void getSalary(int month);

}

// 同级类的形式
class sale extends Employee {
    
    
	public double saleMoney;// 销售额
	public double rate;// 提成率

	@Override
	public void getSalary(int month) {
    
    	
		salary+=saleMoney*rate;
		if(birthdayMonth==month){
    
    
			salary+=100;
		}
		System.out.println("销售员"+name+month+"月份的工资为:"+salary);
	}
}

②成员内部类(全局内部类)

书写在类体中的类

修饰符 class 类名称 {
    
    
    修饰符 class 类名称 {
    
    
        //...
    }
    //...
}
public class A {
    
    
	int aa;
	// 成员内部类
	// 在一个类中书写另一个类
	public class B {
    
    
		// 内部类可以随意访问外部类(包含其他外部类)
		public void b() {
    
    
			// 直接访问当前外部类
			A a = new A();
			// 可以直接访问其他外部类
			A1 a1 = new A1();
			int b=A.this.a;//内部类可以直接使用外部类的属性
			//由于就近原则当出现属性与外部类相同时,使用语法
			//外部类.this.属性名进行指定
		}
	}

	public void a() {
    
    
		B b = new B();
		b.b();
	}
}

class A1 {
    
    
	// 内部类的调用
	public static void main(String[] args) {
    
    
		// 1、间接调用
		// 其他外部类不能直接访问但是书写内部类的外部类可以访问
		// 在外部类声明方法创建内部类对象调用方法
		// 在其他类中创建外部类调用内部类方法
		A a = new A();
		a.a();// 实际调用内部类b方法
		// 2、直接调用
		//直接在其他外部类创建内部类对象
		//语法:外部类.内部类 标识符 =new 外部类().new 内部类();
		A.B b=new A().new B();
		//可以将内部类当做变量,如果想获取一个类的成员变量那么必须先创建这个类的对象
		//之后因为是一个类 如果想使用必须创建对象
		b.b();//直接使用B对象调用b方法
	}

}

成员内部类总结:

1、书写在类体中的类

2、只能由当前类的外部类直接访问

3、可以直接访问外部类(其他外部类)

4、使用同名外部类变量时注意语法 外部类.this.属性名

5、其他外部类访问方式 间接方式(创建外部类通过外部类方法使用内部类) 直接方式(通过外部类直接创建内部类对象)

③局部内部类

如果类是定义在一个方法内部的,那么这就是一个局部内部类。

“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

修饰符 class 外部类名称 {
    
    
    修饰符 返回值类型  外部类方法名称(参数列表) {
    
    
        class 局部内部类名称 {
    
    
            //...
        }
    }
}
public class B {
    
    
	int b = 1;

	// 局部内部类
	// 在方法体中定义的类
	public void b() {
    
    
		int b = 2;
		// 由于方法中变量在方法执行结束后会释放
		// 并且只能由当前方法调用,所以修饰符不能使用public
		class C {
    
    
			int c = 3;

			public void c() {
    
    
				System.out.println(c);
				System.out.println(b);// 可以直接使用方法中的变量
				System.out.println(B.this.b);// 通过固定语法访问同名全局变量
				// 当局部内部类使用方法中的变量时,一般使用final修饰
				// 由于其数据存储空间不同,在执行时可能导致错误
				// 1. new 出来的对象在堆内存当中。
				// 2. 局部变量是跟着方法走的,在栈内存当中。
				// 3. 方法运行结束后,立刻出栈,局部变量就会立刻消失。
				// 4. 但是new出来的对象在堆当中持续存在,直到垃圾回收消失。

			}
		}
		C c = new C();
		c.c();
	}

	public void b1() {
    
    
		// 其他方法不能调用局部内部类,只能通过间接调用
	}

	public static void main(String[] args) {
    
    
		B b = new B();
		b.b();
	}
}

局部内部类总结:

1、书写在方法体中的类

2、只能由当前方法直接访问

3、可以直接访问外部类(其他外部类)

4、使用同名方法所在类变量时注意语法 外部类.this.属性名(对于方法中同名属性不能直接调用建议改名)

5、其他外部类(方法)访问方式 间接方式(通过访问方法的形式进行调用)

6、局部内部类使用方法中变量的值实际过程是创建空间将值复制过来进行使用,要求变量理论不变的原因,是因为回收时机不同,可能导致程序错误(局部内部类不建议使用方法中的属性进行属性的赋值)

修饰内部类的权限

public > protected > (default) > private

定义一个类的时候,权限修饰符规则:

外部类:public / (default)

成员内部类:都可以写,public > protected > (default) > private

局部内部类:什么都不能写,但不是default

匿名内部类

属于局部内部类,书写在方法中但创建类无需类名与class关键字,只需要书写方法体{}

如果接口的实现类(或者是父类的子类)只需要使用唯一的一次。

那么这种情况下就可以省略调该类的定义,而改为使用【匿名内部类】。

匿名内部类用于创建子类或者实现类

接口(父类) 对象名 = new 类名或者接口名称() {
    
    
    //覆盖重写所有抽象方法
};
public interface C {
    
    
	void a();
	void b();
	void c();
}

class Test{
    
    
	public static void main(String[] args) {
    
    
		//匿名内部类就是省略类的声明与命名只书写类体{}
		//一般用于只使用一次的子类或实现类
		C c=new C(){
    
    
			@Override
			public void a() {
    
    
				System.out.println("a");
			}
			@Override
			public void b() {
    
    
				System.out.println("b");
			}
			@Override
			public void c() {
    
    
				System.out.println("c");
			}
		};
		//会直接使用匿名内部类创建一个唯一对象
		//这个对象只有一个,因为没有类
		//相当于使用类体临时创建了一个类并用其创建对象	
		c.a();
	}
}

匿名对象:

创建的对象只调用一次方法那么可以直接使用new 类名().方法()进行使用

注意:

匿名对象与匿名内部类不是同一个东西

匿名对象省略了类的声明

匿名内部类省略了class关键字以及类名

匿名内部类总结

1、匿名内部类由于没有创建类,所以使用父类或者接口声明变量保存遵循多态,只能使用重写的方法以及父类的属性,但是重写的方法可以使用这些属性,只不过不能通过对象进行赋值,(一般在使用匿名内部类的时候不会创建属性只重写方法)

猜你喜欢

转载自blog.csdn.net/weixin_51443782/article/details/109669555