Java _day_12_final、覆写、多态、抽象、接口

本文深入讲解Java中的final修饰符及多态概念,包括final的用途、多态的应用场景及其优缺点,并探讨抽象类、接口、对象等核心内容。

1 final

1.1是什么

final 是个修饰符,表示最终的,不可更改的

1.2能做什么

final修饰的类 不能被继承

final 修饰的成员方法 不能被覆写

final 修饰的变量 不能二次赋值 没有默认值 必须显式赋值

 一般我们把final修饰的静态变量叫做常量 也就是 public static final 数据类型 变量名 = 值 ;

1.3怎么用

package _01_Final;

/**
 * 
 * @author SEC90 2022年1月12日上午9:10:28
 */
public class Final_01 {
	//final 修饰的成员变量 不能二次赋值  没有默认值 
//	final int age ;
	//一般我们把final修饰的静态变量叫做常量,psf会一起出现
	//一般以大写字母命名
	public final static int AGE= 1;
	
	//修饰列表 相互之间无先后顺序 互换位置无影响
	public static void main(String[] args) {
		//final 修饰的变量 不能二次赋值 
//		final int i = 1;
//		i = 2;
	}
}
//final 修饰的类不能被继承
//final class A{
//	
//}
//class B extends A{
//	
//}
// * final 修饰的成员方法 不能被覆写
//class A{
//public final void m1() {
//		
//	}
//}
//
//class B extends A{
//	@Override
//	public  void m1() {
//		
//	}
//}
package _01_Final;

public class Final_02 {
public static void main(String[] args) {
	final Customer a = new Customer("张三",18);
	//age和name 没有被final修饰,final只修饰了c,即c这个对象,是保存age和name的地址,不是两者的变量
	a.age = 19;
	a.name = "李四";
	//不能更改c,因为a被final修饰了
	//	a = null;
}
}
class Customer{
	String name;
	int age ;
	public Customer(String name , int age) {
		this.name= name;
		this.age= age;
	}
		
	}

2 多态

2.1 是什么

父类引用指向子类

父类引用 : 指的是 用父类声明的引用类型变量

指向 : 通过内存地址 可以找到哪个对象

子类对象 : new 子类 创建的堆内存对象
        子类 变量 = new 子类();
        Cat c = new Cat();
        父类类型 变量名 = new 子类();
        Animal a = new Cat();

多态性
            同一操作 作用于不同的对象,可以有不同的解释,产生不同的结果,这就是多态性
            当一件事会有多种不同实现方式的时候 我们选择依赖高层 来拥抱多宗种变化
            本质还是降低类和细节直接的耦合度

2.2相关知识

1 单一职责原则 : 功能单一, 只拥有一种变化, 一个方法尽量和别的方法没有关联 一个类和一个方法只做一件事,这样内聚性更强
            内聚性强就是指聚合性强,优点任意插拔,任意拼凑 灵活性 可变化性强
            聚合 : 组成一个整体的各个部件互不影响,不依赖整体
            组合 : 组成一个整体的各个部件受整体影响,整体消亡,部件也消亡

2 里式替换原则 : 能使用父类的情况下,一定可以使用子类(子类功能一定比父类功能强)

3 依赖倒置原则 : 序要依赖于抽象接口,不要依赖于具体实现, 细节应该依赖于抽象,抽象不应该依赖细节

4 接口隔离原则

5 迪米特法则 : 最少知识原则 只和直接类关联 不管其他类

 6 开闭原则 : 对修改关闭 对扩展开放

2.3 优点

同一操作,作用于不同对象,可以有不同的解释,产生不同的结果,这就是多态性

当一件事会有多种不同实现方式的时候,我们选择依赖高层,来拥抱多种变化

本质还是降低类和细节之间的耦合度.

package _02_Poly;
/**		 
 * @author SEC90
 *2022年1月12日上午9:34:24
 */
public class Poly_01 {
	public static void main(String[] args) {
//		Cat c1 = new Cat();
		//多态
		Animal a1 = new Cat();
		a1.eat();
		a1 = new Dog();
		a1.eat();
		
 	}
}

class Animal{
	public void eat() {
		System.out.println("动物吃东西");
	}
	public void move() {
		System.out.println("动物在移动");
	}
}

class Cat extends Animal{
	@Override
	public void eat() {
		System.out.println("猫吃鱼");
	}
}

class Dog extends Animal{
	@Override
	public void eat() {
		System.out.println("狗吃肉");
	}
}
package _02_Poly;
public class Poly_02 {
	public static void main(String[] args) {
		Animal a = new Cat();
		test(a);
		Animal a1 = new Dog();
		test(a1);
		
	}
	
	//要求 要求能够接收Cat对象,并调用该对象的eat方法
//	public static void  test(Cat cat) {
//		cat.eat();
//	}
	
	//要求 要求能够接收Dog对象,并调用该对象的eat方法
//	public static void  test(Dog dog) {
//		dog.eat();
//	}
	
	//要求 : 要求能够接收所有的动物,并调用该对象的eat方法
	public static void  test(Animal a) {
		a.eat();
	}
}

2.4 缺点

package _02_Poly;
/**
 * 多态的缺点 : 丢失子类特有的属性
 * 
 * 多态进行属性调用:
 * 		1 如果父类没有,直接报错 不管子类有没有
		2 如果父类有 子类没有 直接执行父类
		3 父类和子类都有 成员方法执行子类 因为成员方法可以覆写 其他都执行父类
 * 
 * 多态又叫向上转型
 * 
 * @author SEC90
 *2022年1月12日上午10:43:28
 */
public class Poly_03 {
public static void main(String[] args) {
	//多态
	SupClass supClass = new SubClass();
	//父类子类都有 的成员方法 执行子类
	supClass.m1();
//	父类没有子类有 报错 访问不了
//	supClass.m2();
	//父类有 子类没有 执行父类
	supClass.m3();
	 // 父类子类都有 静态方法 执行父类
//	supClass.m4();
	//成员变量 执行父类
	System.out.println(supClass.i);
	
	
	//此时 由于多态原因 子类特有属性访问不到 想要访问也行 先进行向下转型
	//先发生向上转型才能发生向下转型
	//强制类型转换,不再是多态
	SubClass subClass = (SubClass) supClass;
	subClass.m2();
	
	//如果没有发生向上转型 直接向下转型 会报错
	//_02_Poly.SupClass cannot be cast to _02_Poly.SubClass类型转换异常
//	SupClass supClass2 = new SupClass();
//	SubClass subClass2 =(SubClass) supClass2;
//	subClass2.m2();
	
	//instanceof : 判断 某个对象是否有某个类实例化而来
	if (supClass instanceof SubClass){
		//如果是 在向下转型 不是 就不转 可以避免类型转换异常
		@SuppressWarnings("unused")
		SubClass subClass2 = (SubClass) supClass;
	}
}
}

class SupClass{
	int i = 1;
	public static void m4() {
		System.out.println("父类静态m4");
	}
	public void  m1() {
		System.out.println("父类成员m1");
	}
	public void m3() {
		System.out.println("父类成员m3");
	}
}

class SubClass extends SupClass{
	public static void m4() {
		System.out.println("父类静态m4");
	}
	public void m1() {
		System.out.println("子类成员m1");
	}
	
	public void m2() {
		System.out.println("子类成员m2");
	}
}

package _02_Poly;

/**
 * 多态的几种形式
 * 
 * 父类引用 指向 子类对象
 * 
 * @author SEC90 2022年1月12日下午8:13:24
 */
public class Poly_04 {
	@SuppressWarnings("unused")
	public static void main(String[] args) {

		//直接多态
		Sup sup = new Sub();
		//形参和实参 方法参数列表为父类类型 调用方法传入子类对象
		m1(new Sub());
		//返回值多态 返回值类型时父类类型 但是返回之类对象
		Sup result = m2();
	}
	public static void m1 (Sup sup){
		
	}
	
	public static Sup m2() {
		return new Sub();
	}
}
class Sup{
	
}

class Sub extends Sup{
	
}

package _03_Abstract;

/**
 * abstract : 修饰符, 修饰类 是抽象类,修饰方法是抽象方法
 * 
 * 抽象类,不能实例化对象
 * 
 * 抽象方法没有方法体,值定义功能 没有功能的实现 并且抽象方法必须在抽象类中 抽象类中可以有抽象方法,其他和实体类一样,可以没有抽象方法
 * 
 * final和abstract不能同时出现
 * 
 * @author SEC90 2022年1月12日下午2:16:37
 */
public class Abstract_01 {
	public static void main(String[] args) {
		Animal animal = new  Cat();
		animal.eat();
		animal = new Dog();
		animal.eat();
	}
}

abstract class Animal {
	/**
	 * 动物吃饭功能,抽象方法
	 */
	public abstract void eat();

	public void m1() {

	}
}

class Cat extends Animal {

	// 实现
	@Override
	public void eat() {
		System.out.println("Cat eat fish");
	}
}

class Dog extends Animal {

	// 实现
	@Override
	public void eat() {
		System.out.println("Dog eat meat");
	}
}

package _04_Interface;
/**
 * 接口
 		没有构造方法也不能生成对象
 		
 		可以理解为完全抽像的一个类 里面只有抽象方法和常量
 		
 		但是从1.8开始 , 允许出现 静态方法和默认方法
 		
 		语法 修饰符 interface 接口名{}
 		接口中的抽象方法 不需要加abstract修饰 方法默认都是public abstract
 		接口中 没有变量 只有常量 并且 public static final 可以省略
 		
 		类和接口不再是继承关系 由extends 换成了 implements (实现)
 		
 			接口名 变量 = new 子实现类() 也是会发生多态的
 			
 			一个类只能继承一个类 但是可以实现 N 个接口 以逗号隔开 可以解决单继承功能变弱问题
 				class 类名 implements 接口1,接口2,....{}
 				
 			接口和接口之间 是多继承,多个以逗号隔开
 				interface 接口名 extends 父接口名1,父接口名2,...{}
 			
 			一个类 如果实现了一个接口 那么必须实现接口中所有的抽象方法 否则该类需要加abstract修饰
 			一个抽象类 实现一个接口 可以实现0~N个抽象方法
 			
 			1.7只能有抽象方法
 			1.8 可以有静态方法 可以有default 方法(或理解为成员方法即可)
 				静态方法调用接口名即可
 				default方法需要通过自实现类调用 可以覆写
 			1.9开始支持private方法
 			
 			如果接口和抽象类都能做到一件事 优先使用接口 因为这样会保留类的继承
 			
 * 
 * @author SEC90
 *2022年1月12日下午2:29:31
 */
public class Interface_01 {

}

interface A{
	public static final String name = "xx";
	//psf可以省略
	int age = 12;
	public abstract void m1();
	//public 和 abstract 可以省略
	void m2();
	
	public default  void m3() {
		System.out.println("默认方法");
	}
	public static  void m4() {
		System.out.println("静态方法");
	}
}
interface B{

}

//多继承
interface C extends A,B{
	
}
//多实现 需要实现所有的 抽象 方法
class D implements A,B,C{
	@Override
	public void m1() {
		
	}
	@Override
	public void m2() {
		
	}

}
//抽象类 实现0~N个抽象方法
abstract class E implements A,B,C{
	
}






package _05_Object._01_Equals;

/**
 * 
 * Object 是所有类的祖宗 是Java中提供的根类
 * 
 * 一个类没有显示继承另一个类的时候 默认继承Object
 * 
 * Object xx = new xxx(): 是可以发生多态的
 * 
 * == : 比较基本类型的时候 比较值的大小 但是比较引用类型时 比较的是内存地址
 * 
 * 而内存比较是没有任何价值的 我们一般会比较两个对象的属性值 是否一致 而不是比较两个对象地址是否一致
 * 
 * Equal() : 该方法设计目的 用来比较两个对象是否相等 , 但是默认比较地址
 * 
 * Java中Object 里面的equal 方法 默认比较内存地址 (== ) 需要根据需求覆写
 * 
 * @author SEC90 2022年1月12日下午3:15:11
 */

public class Equals_01 {
	public static void main(String[] args) {
		Student student = new Student(1, "xx");
		Student student2 = new Student(1, "xx");
		//false
		System.out.println(student == student2);
		//true
		System.out.println(student.equals(student2));
	}
}

class Student {
	int id;
	String name;

	public Student(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	// 需求 如果两个学生的ID相同 就认为这两个学生相同
	// 需求 如果两个学生的ID和名字相同 就认为这两个学生相同
	@Override
	public boolean equals(Object obj) {
		// 判断是不是同一个对象
		if (this == obj) {
			return true;
		}
		// 判断obj是否由Student实例化而来
		if (obj instanceof Student) {

			// 向下转型
			Student s = (Student) obj;
			// 对比 像同为TRUE
			if (this.id == s.id&&this.name == s.name){
				return true;
			}
		}

		return false;

	}
}

package _05_Object._01_Equals;

public class Equals_02 {
	public static void main(String[] args) {
		String s1 = new String("xxx");
		String s2 = new String("xxx");
		// false
		System.out.println(s1 == s2);
		// true 因为String中 覆写了 equals方法
		System.out.println(s1.equals(s2));

	}
}

package _05_Object._02_Finalize;
/**
 *finalize : 该方法会在垃圾被回收的时候自动调用,无序程序员手动调用
 * 
 * 垃圾 : 当一个对象,没有更多引用指向它的时候,该对象被视为垃圾数据(就是创建了一个对象,谁也找不到他)
 * 
 * protected void finalize() throws Throwable { }
 * Object中的finalize方法,什么也没有做,需要自己根据需求进行重
 * @author SEC90
 *2022年1月12日下午9:32:30
 */
public class Finalize_01 {
	@SuppressWarnings("unused")
	public static void main(String[] args) {
		Person p = new Person();
		// finalize方法没有回收功能,手动调用的话,只是单纯的方法调用而已
		// p.finalize();
		p = null;
		// 程序员可以建议进行垃圾回收
		// System.gc();
		// for (int i = 0; i < 10000000; i++) {
		// new Person();
		// }
	}
}

class Person {
	@Override
	public void finalize() {
		System.out.println(this + "我要被回收了");
	}
}

package _05_Object._03_ToString;
/**
 * toString : 代表了当前对象的字符串表示形式
 * 
 * 当我们打印一个引用类型变量的时候,会自动调用该对象的toString方法
 * 
 * 而 Object 中默认的toString方法 是打印该对象的内存地址(hash值
 * @author SEC90
 *2022年1月12日下午9:34:19
 */
public class ToString_01 {
	public static void main(String[] args) {
		Person p1 = new Person("张三", 18);
		System.out.println(p1);
		System.out.println(p1.name + ":" + p1.age);
	}
}

class Person {
	public String toString() {
		return this.name + ":" + this.age;
	};

	String name;
	int age;

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值