面向对象(中)学习笔记三
一、instanceof关键字
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明的是父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
如何才能调用子类特有的属性和方法呢?向下转型:使用强制转换符。使用强转时可能出现ClassCastException的异常
instanceof关键字的使用:
a instanceof A:判断关键字a是否是类A的实例。如果是,返回true;如果不是,返回false。
如果x属于类A的子类B,x instanceof A值也为true。
- instanceof的使用情景
为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
如果a instanceof A返回true。并且a instanceof B也返回true。则类B是类A的父类。
向下转型的几个问题
多态练习:
- 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统不可能把父类里的方法转移到子类中。
- 对于实例变量则不存在这样的现象,即使子类定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量,编译运行都看左边。
二、Object类的使用
java.lang.Object
Object类是所有Java类的根父类
数组也作为Object类的子类出现,可以调用Object类中声明的方法。
如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
Object类中的功能(属性和方法)具有通用性
- clone() 克隆一个新的对象
- finalize() 垃圾回收:当一个对象在堆空间中发现没有任何引用指向这个对象了,垃圾回收期就会回收这个对象。在一个对象被回收之前会调用这个方法。
- final、finally、finalize的区别
- getClass() 获取当前对象的所属类。
- hashCode() 返回当前对象的hash值
- Object类无属性
Object只声明了一个空参构造器
面试题:== 和 equals()的区别
==:是一个运算符
1:可以使用在基本数据类型变量和引用数据类型变量中
2:如果比较的是基本数据类型的变量:比较的是两个变量保存的数据是否相等(不一定类型相等)。如果比较的引用数据类型:比较的是两个对象的地址值是否相同。即两个引用是否指向同一个对象实体。
补充:== 符号使用时,必须保证符号左右两边的变量类型一致(可自动转换的基本数据类型除外),否则编译出错。
equals():
1:是一个方法,而非运算符
2:只能适用于引用数据类型
3:Object类中的equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类中定义的equals()和==的作用是相同的:比较的是两个对象的地址值是否相同。
4:像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容(内部的属性)”是否相同。
5:通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同。那么我们就需要对Object类中的equals()进行重写。看举例
重写的原则:比较两个对象的实体内容是否相同。
equals()例题
Object类中toString()的使用
当我们输出一个对象的引用时,实际上就是调用当前对象的toString()方法
Object类中toString()的定义
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode())
}
像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()方法时,返回“实体内容”信息。
自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”。
三、单元测试的方法
Java中的JUnit单元测试
步骤
1、选择当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步
创建Java类,进行单元测试。此时Java类型要求:1、此类是public的。2、此类提供公共的无惨的构造器。
此类中声明单元测试方法。
此时的单元测试方法:方法的权限是public,没有返回值,没有形参此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test
声明好单元测试以后,就可以在方法体内测试相关的代码。
写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test
说明:如果执行结果没有任何异常,绿条。如果执行结果出现异常,红条。
四、包装类的使用
基本数据类型、包装类、String三者之间的转换
基本数据类型—->包装类:调用包装类的构造器。看举例 ```java //基本数据类型 —->包装类:1、调用包装类的构造器 2、调用包装类的valueOf()方法 3、自动装箱 @Test public void test1(){
int num1 = 10;
// System.out.println(num1.toString());
Integer in1 = new Integer(num1);
System.out.println(in1.toString());
//调用valueOf()方法
Integer aa = Integer.valueOf(num1);
Integer in2 = new Integer("123");
System.out.println(in2.toString());
//报异常
// Integer in3 = new Integer(“123abc”); // System.out.println(in3.toString());
Float f1 = new Float(12.3f);
Float f2 = new Float("12.3");
System.out.println(f1);
System.out.println(f2);
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);
Boolean b3 = new Boolean("true123");
System.out.println(b3);//false:忽略大小写之后只要不是true,就会认为是false
Order order = new Order();
System.out.println(order.isMale);//false
System.out.println(order.isFemale);//null
}
-
包装类--->基本数据类型:调用包装类的xxxValue()
```java
//包装类--->基本数据类型:调用包装类Xxx的xxxValue()
@Test
public void test2(){
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.println(f2 + 1);
}
JDK5.0新特性:自动装箱与自动拆箱
- 装箱:将基本类型用它们对应的引用类型包装起来
- 拆箱:将包装类型转换为基本数据类型
从字节码中,我们发现装箱其实就是调用了 包装类的
valueOf()
方法,拆箱其实就是调用了xxxValue()
方法。
Integer i = 10
等价于Integer i = Integer.valueOf(10)
int n = i
等价于int n = i.intValue()
/*
* JDK 5.0 新特性:自动装箱 与自动拆箱
*/
@Test
public void test3(){
// int num1 = 10;
// //基本数据类型-->包装类的对象
// method(num1);
//自动装箱:基本数据类型 --->包装类
int num2 = 10;
Integer in1 = num2;//自动装箱
boolean b1 = true;
Boolean b2 = b1;//自动装箱
//自动拆箱:包装类--->基本数据类型
System.out.println(in1.toString());
int num3 = in1;//自动拆箱
}
public void method(Object obj){
System.out.println(obj);
}
基本数据类型、包装类—->String类型:调用String重载的valueof(Xxx xxx)
//基本数据类型、包装类--->String类型:调用String重载的valueOf(Xxx xxx)
@Test
public void test4(){
int num1 = 10;
//方式1:连接运算
String str1 = num1 + "";
//方式2:调用String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);//"12.3"
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);//"12.4"
}
String类型—->基本数据类型、包装类:调用包装类的parseXxx(String s)方法
//String类型 --->基本数据类型、包装类:调用包装类的parseXxx(String s)
@Test
public void test5(){
String str1 = "123";
//错误的情况:
// int num1 = (int)str1;
// Integer in1 = (Integer)str1;
//可能会报NumberFormatException
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
包装类常见面试题
package com.atguigu.java2;
import org.junit.Test;
/*
* 关于包装类使用的面试题
*
*
*/
public class InterviewTest {
@Test
public void test1() {
Object o1 = true ? new Integer(1) : new Double(2.0);//三元运算符会统一类型,
System.out.println(o1);// 1.0
}
@Test
public void test2() {
Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);// 1
}
@Test
public void test3() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],
//保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在
//-128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
Integer x = 128;//相当于new了一个Integer对象
Integer y = 128;//相当于new了一个Integer对象
System.out.println(x == y);//false
}
}