04 面向对象:Object类、equals重写、final关键词、抽象类和抽象方法、接口、对象转型

一、Object类

Object:超类、基类;它是所有类的父类。
一个类没有明确继承其他类,则默认继承Object类。

1、equals()方法

equals()功能:比较两个对象的内存地址是否相同

    //equals底层
    		public boolean equals(Object obj) {
           	return (this == obj);
      	 	}

在String类中,“==”比较对象的内存地址是否相同,equals比较内容是否相同。

对于基本数据类型,"=="比较内容是否相同。

2、toString()方法

把对象转为字符串,打印对象时被调用。

    //toString()底层
    	 	public String toString() {
        		return getClass().getName() + "@" + Integer.toHexString(hashCode());
    		}

例:

     public static void main(String[] args) {
     	Object o1 = new Object();
    	Object o2 = new Object();
    	System.out.println(o1.equals(o2));
    	//输出对象,默认调用toString()
    	System.out.println(o1);//java.lang.Object@1cd0888
    	System.out.println(o1.toString());//java.lang.Object@1cd0888
    	
    	//toString显示代码实现
    	//获取到的是在方法区中Object.class对象
    	Class objClass = o1.getClass();
    	//获取该类的全路径:java.lang.Object
    	String name = objClass.getName();
    	System.out.println(name);//java.lang.Object
    	//获取该对象的hash值
    	int hashCode = o1.hashCode();
    	//再把十进制的hash值转换为十六进制
    	String hexString = Integer.toHexString(hashCode);
    	System.out.println(hexString);//1cd0888
    }

3、getClass()

获取当前类的字节码文件的对象。
见上述代码。

4、hashCode()

获取对象的hash值。见上述代码。

二、重写Object类中的equals方法

String类的equals方法是重写的,与Object类功能不一样。
“==”比较对象的内存地址是否相同,equals比较内容是否相同。

为什么要重写equals和hashCode?

场景:酒店用身份证查询入住 在程序中:登记的前台好比哈希算法,名字是对比好比 equals
方法,身份证号的对比好比 hashcode 方法只有equals 和 hashcode 都满足的时候才能确保是同一个对象。

当我们重写一个类的 equals 方法时就应当连同重写 hashcode 方法,并且两个方法应满足: 1:一致性,即:当两个对象
equals 比较为 true,那么 hashcode 值应当相等,反之亦然,因为当两个对象hashcode 值相等,但是 equals
比较为 false,那么在 HashMap 中会产生链表,影响查询性能。 2:成对重写,即重写 equals 就应当重写 hashcode。

    String str1 = new String("123");
    	String str2 = new String("123");
    	System.out.println(str1==str2);//false
    	System.out.println(str1.equals(str2)); //true
    	System.out.println(str1);//123

仿照String类型的equals方法和toString方法重写Object类的equals和toString,将该类命名为MyString:

    public class MyString {
    	private String value;
    	public MyString(String value) {
    		this.value = value;
    	}
    		@Override
    		public boolean equals(Object obj) {
    
    			MyString m2 = (MyString) obj;
    			
    			//把this(m1)和m2对象里存的value值-“123”取出来,并转换为字节数组
    			char[] charArray1 = this.value.toCharArray();
    			char[] charArray2 = m2.value.toCharArray();
    			
    			if(charArray1.length != charArray2.length){
    				return false;
    			}
    			
    			for (int i = 0; i < charArray1.length; i++) {
    				if(charArray1[i] != charArray2[i]){
    					return false;
    				}
    			}
    			return true;
    		}
    
    		@Override
    		public String toString() {
    			return value;
    		}
    }
    MyString m1 = new MyString("123");
    		MyString m2 = new MyString("123");
    		System.out.println(m1 == m2);//false
    		System.out.println(m1.equals(m2));//true
    		System.out.println(m1);//123

三、final关键词

final:最终的
* 修饰类:类不能被继承
* 修饰方法:方法不能被重写
* 修饰变量:变量不能被重新赋值----常量
* ps:
* 1.常量存储在常量池里,项目结束时才会被销毁
* 2.常量的命名规范:单词全部大写,单词与单词之间用下划线隔开
*
* 面试题:String类为什么是final类
* 1.遵循了String类的不变性
* 2.用final修饰的类里的方法自动成为JVM里的内联函数,调用效率更高

    	//此类不能被继承
	    //public final class Father {
	    public class Father {
    
	    //  子类不能被重写
	    //	public final void eat(){
	    	public void eat(){
    		System.out.println("哈哈");
    		
  		//常量
  		final String CLASS_ID = "1903";
  		System.out.println(CLASS_ID);
    	}
    }

四、抽象类和抽象方法

抽象类定义规则:
(1)抽象类和抽象方法都必须用abstract关键字修饰。
(2)抽象类不能被直接实例化,也就是不能直接用new关键字去产生对象。
(3)抽象方法只需声明,而不需实现。
(4)含有抽象方法的类必须被声明为抽象类,抽象类的子类必须重写所有的抽象方法后才能被实例化,否则这个子类还是个抽象类。

    //抽象类
    public abstract class Person {
    //抽象方法:交给非抽象的子类去重写
    	public abstract void eat();
    	}
  • 1.抽象类里可以有属性吗?可以
  • 2.抽象类里可以有非抽象方法吗?可以
  • 3.抽象类可以创建对象吗?不可以,创建的是匿名子类的对象
  • 4.抽象类是否有构造方法?有
  • 5.抽象类的构造方法有什么用?初始化数据
  • 6.抽象类里可以没有抽象方法吗?可以,没意义
  • 7.如果父类是抽象类,则子类必须重写父类的抽象方法?不一定,子类如果是抽象类,就可以不去重写

Person是一个抽象类,创建的不是Person的对象
匿名内部类:创建了一个没有名的类,继承了Person,重写了eat方法

    Person person = new Person() {
    			@Override
    			public void eat() {
    			}
    		};

需求:老师骑着自行车上班
需求优化:自行车 --> 小汽车 --> 飞机
主方法

    public static void main(String[] args) {
  
    		//多态:子类对象指向父类引用
    		Teacher t = new Teacher();
			Transport tool = new Car();
			t.start(tool);
			t.stop(tool);
    }

老师类

    public class Teacher {
    
    	public void start(Transport tool) {
    		tool.start();
    	}
    	public void stop(Transport tool) {
    		tool.stop();
    	}
    }

父类-交通工具类-抽象类

    public abstract class Transport {
    	abstract void start();
    	abstract void stop();
    }

子类-汽车

    public class Car extends Transport{
        	@Override
        	void start() {
        		System.out.println("小汽车启动了");	
        	}
        	@Override
        	void stop() {
        		System.out.println("小汽车停止了");
        	}
        }

子类-自行车

    public class Bike extends Transport{
    
    	@Override
    	void start() {
    		System.out.println("自行车启动了");
    	}
    	@Override
    	void stop() {
    		System.out.println("自行车停止了");
    	}
    }

在这里插入图片描述

自创同类例子:
需求:一个人选择了一位英雄,并了解其技能。
主方法

    public static void main(String[] args) {
    Person p = new Person("小羊同学");
    	Hero hero= new Kass("kass");
    	System.out.println(p.getName()+"选择的英雄是:"+hero.getName()+",他的技能是:");
    	hero.Skills();
    }
    }

父类-英雄类(名字,抽象方法)

    public abstract class Hero {
    	private String name;
    
    	public Hero() {}
    	public Hero(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    	public abstract  void Skills();
    }

子类卡萨丁(姓名,方法)

    public class Kass extends Hero{
    	public Kass() {}
    	public Kass(String name) {
    		super.setName(name);
    	}
    	@Override
    	public void Skills() {
    		System.out.println("Q能触发魔法护盾!");
    		System.out.println("主E吊打Yasuo");
    	}
    }

子类奥拉夫(姓名,方法)

    public class Aolafu extends Hero{
    	public Aolafu() {}
    	public Aolafu(String name) {
    		super.setName(name);
    	}
    	@Override
    	public void Skills() {
    		System.out.println("斧子可刷新");
    		System.out.println("铁头娃,B键已扣");	
    	}
    }

人类

    public class Person {
    	String name;
    	public Person() {}
    	public Person(String name) {
    		super();
    		this.name = name;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	public void pickHero(Hero hero) {
    		hero.Skills();
    	}
    }

输出结果
在这里插入图片描述

五、接口

接口:特殊的抽象类
与抽象类的区别:
(1)接口里的数据成员必须初始化,且数据成员均为常量;
(2)接口里的方法必须全部声明为abstract,也就是说,接口不能像抽象类一样保有一般的方法,必须全部是“抽象方法”。

利用接口打造新的类的过程,称之为接口的实现(implementation)。

有的人可能会觉得这样做与抽象类并没有什么不同,在这里需要再次提醒的是:接口是Java实现多继承的一种机制,一个类只能继承一个父类,但如果需要一个类继承多个抽象方法的话,就无法实现,因此出现了接口的概念。一个类只可以继承一个父类,但却可以实现多个接口。

一个接口可以同时继承多个接口,也就是同时继承了多个接口的抽象方法与常量。

ps:
1.接口更多的是描述一个标准
2.接口里只能有常量或者抽象方法
应用场景:抽象类里只有常量或抽像方法时用接口代替

类 与 类:单继承 A extends B
类 与 接口:多实现 A implements B,C
接口与接口:多继承 A extends B,C,D

    public abstract interface IPerson{
    	public abstract void eat();
    }

简写,接口默认abstract,接口名以I开头。

    public interface IPerson{
    	public void eat();
    }
//实现类  实现  多接口
    public class Chinese implements IPerson,I1,I2
//一个类继承另一个类并实现多个接口
	public class Japanese extends Object implements IPerson,I1,I2

OCP-开闭原则:
* O - open :对创建欢迎的
* C - close:对修改关闭的
* p - princeple:原则

需求:选择电脑上的硬件,了解其功能

    public static void main(String[] args) {
    		Computer computer = new Computer();
    		IUSB usb = new Disk();
    		computer.connection(usb);
    	}

电脑类

    public class Computer {
    	public void connection(IUSB usb) {
    		usb.use();
    	}
    }

接口类

    public abstract interface IUSB {
    	public abstract void use();
    }

硬盘类

    public class Disk implements IUSB{
    	@Override
    	public void use() {
    		System.out.println("我是硬盘");	
    	}
    }

鼠标类

    public class Mouse implements IUSB{
    	@Override
    	public void use() {
    		System.out.println("我是鼠标");	
    	}
    }

六、对象转型

向上转型:
子类类型转父类类型
可以获取父类非私有化的属性和方法
可以获取子类重写父类后的方法
**缺点:**不能获取到子类的属性及方法

父类

    public class Father {
    	String fatherAtrr = "父类属性";
    	public void fatherMethod(){
    		System.out.println("父类方法");
    	}
    	public void fatherMethod2(){
    		System.out.println("父类方法");
    	}
    }

子类

    public class Son extends Father{
    	String sonAtrr = "子类属性";
    	public void sonMethod(){
    		System.out.println("子类方法");
    	}
    	public void fatherMethod2(){
    		System.out.println("子类重写父类的方法");
    	}
    }
    public static void main(String[] args){
    		Father f = new Son();
    		System.out.println(f.fatherAtrr);
    		f.fatherMethod();
    		f.fatherMethod2();
    }

在这里插入图片描述

向下转型(不安全)
父类类型转子类类型

    public class Dog extends Animal{
    	String attr = "狗";
    }
    public class Cat extends Animal{
    	String attr = "猫";
    }
	public static void main(String[] args){
    	//下转型一定要用instancdof判断
   		Animal an = new Dog();
   		if(an instanceof Cat){//判断an这个引用对应的对象是否是Cat的类型
   			
   			Cat cat = (Cat) an;//下转型
   			System.out.println(cat.attr);
   			
   		}else if(an instanceof Dog){
   			Dog dog = (Dog) an;
   			System.out.println(dog.attr);//下转型
   		}
   	}

输出:狗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值