目录
1、面向对象特征之二:继承性
1.1、继承性的好处
- 减少了代码的冗余,提高了代码的复用性
- 便于功能的扩展
- 为之后多态性的使用,提供了前提
1.2、继承性的格式
Class A extends Class B{}
Class A ——子类
ClassB ——父类子类继承了父类之后,就可以调用父类的属性和方法,还可以声明自己特有的属性或方法,实现功能拓展
》》特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构
只是因为封装性的影响,使得子类不能直接调用父类的结构而已
1.3、继承性的规则
- 一个类阔以被多个子类继承
- 类的单继承性 :一个类只能有多个父类
- 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
- 子类继承父类以后,就获取了直接父类以及间接父类中声明的属性和方法
- 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()方法得到哈希值,该哈希值再被十六进制转换,得到最终值)
2、
Person 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 + "]";
}
2、
Person 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