Java基础——4、面向对象(中)——继承、重载、重写、多态、equals、包装类、装箱拆箱

接上一章
面向对象(上)

1、面向对象特征之二:继承性

在这里插入图片描述

1.1、继承性的好处

  • 减少了代码的冗余,提高了代码的复用性
  • 便于功能的扩展
  • 为之后多态性的使用,提供了前提

1.2、继承性的格式

Class A extends Class B{}
Class A ——子类
ClassB ——父类

子类继承了父类之后,就可以调用父类的属性和方法,还可以声明自己特有的属性或方法,实现功能拓展
》》特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构
只是因为封装性的影响,使得子类不能直接调用父类的结构而已

1.3、继承性的规则

  1. 一个类阔以被多个子类继承
  2. 类的单继承性 :一个类只能有多个父类
  3. 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
  4. 子类继承父类以后,就获取了直接父类以及间接父类中声明的属性和方法
  5. Object类是所有类的直接父类或间接父类

1.4、Eclipse——Debug模式

在这里插入图片描述

2、方法的重写

子类继承父类以后,阔以对父类中同名同参数的方法,进行覆盖操作
应用:重写以后,当创建子类对象以后,通过子类对象调用,执行的是子类重写父类的方法

2.1、谈谈方法重载和重写的区别???

重载

在同一个类中,存在多个同名的方法,
只要他们的参数个数或者参数类型不同即可

重写——Override

子类继承父类
1、方法名相同,
2、形参列表相同
3、子类方法的权限修饰符范围必须 >= 父类的修饰范围
》》特殊情况:子类不能重写父类中声明为private权限的方法
4、子类方法的返回值类型可以是父类返回值类型本身,返回值类型也可以是其子类
5、子类方法抛出的异常要 <= 父类抛出的异常
6、子类、父类同名同参数的方法都声明为非static的方法才可以考虑是不是重写,声明为static的一定不是重写

在这里插入图片描述

3、四种访问权限修饰符

在这里插入图片描述

4、关键字:super

super理解为:父类的
可以用来super.属性、方法、 构造器

特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的
使用"super.方法"的方式,表明调用的是父类中被重写的方法。

5、子类对象实例化过程

子类继承父类后,就获取了父类中声明的属性和方法
创建子类的对象时,在堆空间中,就会在这个对象中加载父类声明的属性和方法
只要父类的结构加载了,子类才能够调用父类的结构(属性和方法)

6、面向对象特征之三:多态性

6.1、理解多态性:

可以理解为一个事物的多种形态

6.2、何为多态性:Person p = new man();

对象的多态性,父类的引用指向子类的对象(或子类的对象赋给父类的引用)

6.3、多态的使用,虚拟方法调用

有了对象的多态性以后,我们在编译器,只能调用父类中声明的方法
,但在运行期,我们实际执行的是子类重写父类的方法。

6.4、总结:

编译,看左边;运行,看右边

6.5、多态性的使用前提:

1、类要有继承关系
2、要有方法的重写

3、对象的多态性。只适用于方法,不适用于属性(编译和运行看左边)

6.6、多态性面试题:

Person p = new Man();
p.eat();
问:多态是编译时行为还是运行时行为?
如何证明?
答:属于运行时行为,因为最终执行的是子类的重写的方法

6.7、方法的重载和重写

在这里插入图片描述

6.8、如何才能调用子类特有的属性和方法?

有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致
编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

6.8、instanceof关键字的使用

  • a instanceof A: 判断对象a是否是类A的实例。
  • 如果是,返回true ; 如果不是,返回false。

7、Object类的使用

Object类是所有Java类的根父类
如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
Object类中的功能(属性、方法)就具有通用性,所有子类都可以调用使用

7.1、clone()——创建对象的第二种方法

7.2、==和equals()的区别???

在这里插入图片描述

7.2.1 ==

可以使用在基本数据类型变量和引用数据类型变量中
》如果比较的是基本数据类型变量 : 比较两个变量保存的数据是否相等。(不一 定类型要相同)
》如果比较的是引用数据类型变量 : 比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

//比较基本数据类型
public static void main(String[] args) {
		int a = 10;
		int b = 10;
		double c = 10.0;
		char d = 10;
		System.out.println(a==b);//true
		System.out.println(a==c);//true  原因:int类型转为double类型了,所以相等
		System.out.println(a==d);//true

		char c1 = 'A';//A放在栈,它对应的值65是放在堆的
		char c2 = 65;
		int a1 = 65;
		System.out.println(c1 == c2);//true
		System.out.println(c1 == a1);//true

	}
//比较引用数据类型
		Person p = new Person();
		Person p1 = new Person();
		String s1 = new String("s1");
		String s2 = new String("s2");
		System.out.println(p == p1);//false 引用类型比较的就是地址值是否相等
		System.out.println(s1 == s2);//false

7.2.2 equals()

是一个方法,而非运算符
只能适用于引用数据类型

Object类中equals()定义 看源码:
发现Object类中定义的这个equals方法底层作用和 == 是一样的:最终比较的是两个对象的地址值
在这里插入图片描述

		Person p = new Person();//自定义类
		Person p1 = new Person();
		//自定义类 默认 调用的是Object定义的equals方法
		System.out.println(p.equals(p1));//false


		//String类、Date、File、包装类等都重写了Object的equals方法
		//重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的 " 实体内容 " 是否相同。所以为true
		String s1 = new String("s1");//String类
		String s2 = new String("s1");
		System.out.println(s1.equals(s2));//true

问题:如何让自定义类的 p.equals(p1) 结果为true呢?

答:重写

通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的”实体内容指的实体类的属性“是否相同,那么,
我们就需要对Object类中的equals()进行重写

例题如下:
创建Person类,设置私有属性,get/set方法,构造方法, 重写equals()方法

public class Person {
	private String name;
	private int age;
	
	public Person() {
		super();
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	//自定义类重写equals方法
	@Override
	public boolean equals(Object obj) {
		if (this == obj){
			return true;
		}
		if (obj instanceof Person){//instanceof 判断obj是否属于Person的实例
			Person p =(Person)obj;
			//比较两个对象的每个属性是否都相同
			if (this.age == p.age && this.name.equals(p.name)) {
				return true;
			}
		}
		return false;
			
	}	
}


测试类代码:
		Person p = new Person("小白",20);//自定义类Person类  重写了equals方法
		Person p1 = new Person("小白",20);
		System.out.println(p.equals(p1));//true
		
结果为true

7.3、Object类中toString()的使用:

在自定义类重写toStrig()之前,默认调用的是Object类中的toStrig()方法

7.3.1、重写前

1、默认调用Object类的toString方法——源码如下
	public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
//包名类名 + @ + (通过hashCode()方法得到哈希值,该哈希值再被十六进制转换,得到最终值)
2Person p2 = new Person("小白",20);
		System.out.println(p2);
		//打印结果如下:
		//com.demo10.test11_1.Person@15db9742   该类在项目中的位置+@+通过哈希方法得到的值再转化为十六进制的一个数

7.3.2、重写后

1、在实体类中重写toString()方法
	//重写toString方法
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

2Person p2 = new Person("小白",20);
		System.out.println(p2);
3、重写之后打印的输出结果如下:
		Person [name=小白, age=20]

8 、Junit单元测试

步骤:
1.
选中当前工程- 右键选择: build path - add libraries - JUnit4-下一步
工程中出现如下的JUnit4才行:
在这里插入图片描述
2.
创建Java类,进行单元测试。
此时的Java类要求: 此类是public 此类提供公共的无参的构造器
3、
此类中声明单元测试方法
此时的单元测试方法:方法的权限是public ,没有返回值,没有形参
4、
此单元测试方法上需要声明注解: @Test ,并在单元测试类中导入: import org . junit. Test;
5、
声明好单元测试方法以后,就可以在方法体内测试相关的代码。
6、
写完代码以后,左键双击单元测试方法名,右键: run as - JUnit Test

import org.junit.Test;

public class JunitTest {
	@Test
	public void testEquals(){
		String s1="M";
		String s2="M";
		System.out.println(s1.equals(s2));
	}

}

结果:
如果执行结果没有异常:绿条
在这里插入图片描述
在这里插入图片描述

如果执行结果出现异常:红条

import java.util.Date;

import org.junit.Test;

public class JunitTest {
	@Test
	public void testEquals(){
		String s1="M";
		String s2="M";
		System.out.println(s1.equals(s2));
		
		//以下是错误代码,不能转换,会出现红条
		Object obj = new String("A");
		Date date = (Date)obj;
	}

}

在这里插入图片描述

9 、包装类(Wrapper)的使用

包装类属于引用类型
在这里插入图片描述

9.1、总结:基本类型、包装类与String类间的转换

在这里插入图片描述

9.2、基本数据类型—>包装类

9.2.1、调用包装类的构造器

举例
public class JunitTest {
	@Test
	public void testEquals(){
		int i = 10;
		Integer i1 = new Integer(i);
		System.out.println(i1.toString());//包装类默认重写了toString方法,不用显式调用
		//类似的Float
		Float f1 = new Float(13.1f);
		System.out.println(f1);//13.1
		//其他包装类同上
	}

}

9.2.2、JDK5.0新特性——自动装箱

//自动装箱
		int num1 = 10;
		Integer in1 = num1;
		System.out.println(in1);//10

9.3、包装类—>基本数据类型

9.3.1、调用包装类的xxxValue()

public class JunitTest1 {
	@Test
	public void test1(){
		Integer i = new Integer(12);
		int intValue = i.intValue();//转换为基本数据类型之后可以做运算
		System.out.println(intValue+1);
	}

}

9.3.2、JDK5.0新特性——自动拆箱

		//自动拆箱
		Integer i1 =new Integer(23);//包装类——>基本数据类型
		int i2 = i1;
		System.out.println(i2);//23

9.4、包装类、基本数据类型——>String类型

public class JunitTest1 {
	@Test
	public void test1(){
		//方式一:连接运算
		int n1 = 10;
		String s1 = n1 + "";
		//方式二:调用String重载的valueOf(XXX xxx)
		float f1 = 13.2f;
		String valueOf = String.valueOf(f1);
		System.out.println(s1);//10
		System.out.println(valueOf);//13.2
	}
}

9.5、String类型——>包装类、基本数据类型

public class JunitTest1 {
	@Test
	public void test1(){
		String s1 = "123";
		int parseInt = Integer.parseInt(s1);
		
		String s2 = "true";
		boolean parseBoolean = Boolean.parseBoolean(s2);
		System.out.println(parseInt);//123
		System.out.println(parseBoolean);//true
	}
}

9.6、包装类面试题

【例题】
import org.junit.Test;

public class JunitTest1 {
	@Test
	public void test1(){
		//例题1、false
		Integer i1 = new Integer(1);
		Integer j1 = new Integer(1);
		System.out.println(i1 == j1);//false
		//例题2、true
		Integer i2=1;
		Integer j2=1;
		System.out.println(i2 == j2);//true
		//例题3、false
		Integer i3=128;
		Integer j3=128;
		System.out.println(i3 == j3);//false
	}
}

【分析】
问题1、为什么是false?
       因为包装类属于引用类型,== 底层比较的是new出来的地址值 二者不一致 所以是false
       
问题2、换做包装类之后,为什么就是true了?
		Integer内部定义了IntegerCache结构,IntegerCache中定义了 Integer[]这个数组,
该数组中保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在 - 128~127范围内时,
可以直接使用该数组中的元素,不用再去new了,比较的是数组里面的同一个元素,所以结果是true。目的:提高效率

问题3、换做包装类之后,值是128就不是true了?
		如果超出了这个-128~127范围,相当于new了一个Integer对象
		例如128就超出了这个数组里面的范围,就会去new一个新的,
		而不是直接使用 Integer[]数组里面的数,导致比较的是地址值,所以是false


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值