JAVA基础学习笔记(7):多态、Object类、单元测试、包装类

目录

  • 1 多态
    • 1.1 多态的概念
    • 1.2 多态的使用
    • 1.3 虚拟方法调用
    • 1.4 注意
    • 1.5 向上转型与向下转型
      • 1.5.1 instacneof关键字
  • 2 Object类的使用
    • 2.1 Object类特点
    • 2.2 Object中的方法
    • 2.3 ==操作符与equals方法的比较
      • 2.3.1 ==操作符
      • 2.3.2 equlas()方法
      • 2.3.3 ==操作符与equals方法的例子
    • 2.4 toString方法
  • 3 单元测试
    • 3.1 eclipse中单元测试的步骤
    • 3.2 单元测试的例子
  • 4 包装类
    • 4.1 包装类的种类
    • 4.2 装箱与拆箱
    • 4.3 基本数据类型、包装类、String类的转换
    • 4.4 需要注意的代码
  • 本节练习
    • ex1
    • ex2
    • ex3

1 多态

1.1 多态的概念

多态可以理解为一个事物的多种形态。
对象的多态性:父类的引用指向子类的对象(或子类的对象赋值给父类的引用)
Java引用变量有两个类型:编译时类型运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
编译时,看左边;运行时,看右边

1.2 多态的使用

例1:人、男人、女人
Person.java:

public class Person {
	String name;
	int age;
	int id = 1001;
	
	public void eat() {
		System.out.println("人:吃饭");
	}
	
	public void walk() {
		System.out.println("人:走路");
	}
}

Man.java:

public class Man extends Person {

	boolean isSmoking;	
	int id = 1002;
	
	public void earnMoney() {
		System.out.println("男人挣钱");
	}
	
	@Override
	public void eat() {
		System.out.println("男人吃肉,多长肉");
	}
	
	@Override
	public void walk() {
		System.out.println("男人走路带风");
	}
}

Woman.java:

public class Woman extends Person {
	
	boolean isBeauty;
	
	public void goShopping() {
		System.out.println("女人喜欢买买买");
	}
	
	@Override
	public void eat() {
		System.out.println("女人少吃为了减肥");
	}
	
	@Override
	public void walk() {
		System.out.println("女人走路的样子很好看");
	}
}

PersonTest.java:

public class PersonTest {
	public static void main(String[] args) {
		
		Person p1 = new Person();
		p1.eat();
		
		Man m1 = new Man();
		m1.eat();
		m1.earnMoney();
		
		System.out.println("************************");
		Person p2 = new Man();
		//多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用
		p2.eat();
		p2.walk();
		//对象的多态只适用于方法,不适用于属性
		System.out.println(p2.id); //1001
	}
}

例2:生动的多态例子
AnimalTest.java:

public class AnimalTest {
	public static void main(String[] args) {
		
		AnimalTest test = new AnimalTest();
		test.func(new Dog());
		test.func(new Cat());
	}
	
	public void func(Animal animal) {
		animal.eat();
		animal.shut();
	}
}

class Animal{
	public void eat() {
		System.out.println("动物:进食");
	}
	public void shut() {
		System.out.println("动物:叫");
	}
}

class Dog extends Animal{
	public void eat() {
		System.out.println("狗:吃肉和骨头");
	}
	public void shut() {
		System.out.println("狗:汪!汪!汪!");
	}
}

class Cat extends Animal{
	public void eat() {
		System.out.println("猫:吃鱼和老鼠");
	}
	public void shut() {
		System.out.println("猫:喵!喵!喵!");
	}
}

1.3 虚拟方法调用

在多态情况下,子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。

Person e = new Student();
e.getInfo();

编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类 的getInfo()方法,也可以叫做动态绑定。

1.4 注意

成员变量不具有多态性。
对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法, 这称为“早绑定”或“静态绑定”。
对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体 方法,这称为“晚绑定”或“动态绑定”。

1.5 向上转型与向下转型

有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
可以通过向下转型的方法来解决这个问题。
JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第1张图片

1.5.1 instacneof关键字

在进行强制转换时,很可能产生ClassCastException异常,需要使用instanceof关键字来进行判断。
a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
如果 a instanceof A返回true,则 a instanceof B也返回true。其中类B是类A的父类。

//Person、Man、Woman见1.2的例1
public class PersonTest {
	
	public static void main(String[] args) {	
		Person p1 = new Man();
		p1.name = "TOM";
		//p1.isSmoking;
		//p1.earnMoney();
		//有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致
		//编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
		
		//向下转型:强制类型转化符
		Man m1 = (Man)p1;
		m1.isSmoking = true;
		m1.earnMoney();
		
		if(p1 instanceof Woman) {
			Woman w1 = (Woman)p1;
			w1.goShopping();
			System.out.println("p1 为 Woman 的实例");
		}
		if(p1 instanceof Man) {
			Man m2 = (Man)p1;
			System.out.println("p1为Man的实例");
		}
		if(p1 instanceof Person) {
			System.out.println("p1为Person的实例");
		}
		if(p1 instanceof Object) {
			System.out.println("p1为Object的实例");
		}	
	}
}

2 Object类的使用

2.1 Object类特点

1.Object类是所有的 Java类的根父类
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
3.Object中的属性和方法有通用性

2.2 Object中的方法

注意:Object类中没有属性!
方法:clone()、equals()、finalize()、getClass()、hasCode()、notify() 、notifyAll() 、toString() 、wait()

2.3 ==操作符与equals方法的比较

2.3.1 ==操作符

1.可以使用在基本数据类型变量和引用数据类型变量中
2.如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
补充: == 符号使用时,必须保证符号左右两边的变量类型一致。

2.3.2 equlas()方法

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()进行重写.
重写的原则:比较两个对象的实体内容是否相同.

2.3.3 ==操作符与equals方法的例子

EqualsTest.java:

public class EqualsTest {
	public static void main(String[] args) {
		//基本数据类型
		int i = 10;
		int j = 10;
		System.out.println(i == j); //true
		double k = 10.0;
		System.out.println(i == k); //true
		char a1 = 'A';
		char a2 = 65;
		System.out.println(a1 == a2);//true
		int a3 = 65;
		double a4 = 65;
		System.out.println(a1 == a3); //true
		System.out.println(a2 == a4); //true
		//引用数据类型
		Customer cust1 = new Customer("Tom", 18);
		Customer cust2 = new Customer("Tom", 18);
		System.out.println(cust1 == cust2); //false
		
		String s1 = new String("abcd");
		String s2 = new String("abcd");
		System.out.println(s1 == s2); //false
		System.out.println("**********************");
		System.out.println(cust1.equals(cust2));//false 可以通过重写来让变为true
		System.out.println(s1.equals(s2));//true
	}
}

Customer.java:

public class Customer {
	private String name;
	private int age;
	
	public Customer() {
		super();
	}
	
	public Customer(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 == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Customer other = (Customer) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	//重写原则:比较两个对象的实体内容是否相同(name、age)  
	//手动实现,存在漏洞!!!!
//	@Override
//	public boolean equals(Object obj) {
//		if(this == obj) {
//			return true;
//		}
//		if(obj instanceof Customer) {
//			Customer cust = (Customer)obj;
//			return this.age == cust.age && this.name.equals(cust.name);
//		}else {
//			return false;
//		}
//	}
}

2.4 toString方法

1.toString()方法在Object类中定义,其返回值是String类型,返回类名和它 的引用地址。

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

2.像String、Date、File、包装类等都重写了Object类中的toString()方法。 使得在调用对象的toString()时,返回"实体内容"信息。
3.自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"

3 单元测试

3.1 eclipse中单元测试的步骤

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

3.2 单元测试的例子

JUnitTest.java:

import org.junit.jupiter.api.Test;
public class JUnitTest {
	@Test
	public void  testEquals() {
		String s1 = "MM";
		String s3 = "MM";
		System.out.println(s1.equals(s3));
	}
}

运行后的结果:
JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第2张图片
如果执行结果没有任何异常:绿条
如果执行结果出现异常:红条

4 包装类

4.1 包装类的种类

JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第3张图片

4.2 装箱与拆箱

装箱:基本数据类型包装成包装类实例
拆箱:获得包装类对象中包装的基本变量
JDK1.5之后,支持自动装箱,自动拆箱,前提是类型必须相互匹配。

4.3 基本数据类型、包装类、String类的转换

JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第4张图片

import org.junit.jupiter.api.Test;
public class WrapperTest {
	//基本数据类型->包装类 :调用包装类的构造器
	@Test
	public void test1() {
		int num = 10;
		Integer int1 = new Integer(num);
		System.out.println(int1);
		Integer int2 = new Integer("10");
		System.out.println(int2);
		
		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");
		Boolean b3 = new Boolean("TrUe123"); //Boolean若未赋值,初始化为null
		System.out.println(b1); //true
		System.out.println(b2); //true
		System.out.println(b3); //false
	}
	
	//包装类->基本数据类型:调用包装类的Xxx的xxValue()方法
	@Test
	public void test2() {
		Integer int1 = new Integer(12);
		int a = int1.intValue();
		System.out.println(a + 1);
		
		Double b1 = new Double(10.25);
		double b = b1.doubleValue();
		System.out.println(2 * b);
	}
	
	//JDK 5.0 新特性:自动装箱与自动拆箱
	@Test
	public void test3() {
		//自动装箱:基本数据类型->包装类
		int num1 = 10;
		Integer num2 = num1;//自动装箱
		
		boolean b1 = true;
		Boolean b2 = b1; //自动装箱
		
		//自动拆箱:包装类->基本数据类型
		Integer num3 = new Integer(100);
		int num4 = num3;//自动拆箱
	}
	
	//基本数据类型、包装类——>String类型:调用String重载得valueOf()
	@Test
	public void test4() {
		int num = 10;
		//方式一:连接运算
		String str1 = num + "";
		//方式二:调用String的valueOf
		float f1 = 1.23f;
		String str2 = String.valueOf(f1);
		System.out.println(str1);
		System.out.println(str2);
	}
		
	//String类型——>基本数据类型、包装类:调用包装类的parseXxx(String s)
	@Test
	public void test5() {
		String str = "123";
		
		int num = Integer.parseInt(str);
		System.out.println(num + 1);
		
		String str1 = "true1";
		boolean b1 = Boolean.parseBoolean(str1);
		System.out.println(b1);//false   注意:返回不标准的true也是false
	}
}

4.4 需要注意的代码

public void method1() { 
	Integer i = new Integer(1); 
	Integer j = new Integer(1); 
	System.out.println(i == j);//false
	Integer m = 1; 
	Integer n = 1; 
	System.out.println(m == n);//true
	Integer x = 128; 
	Integer y = 128; 
	System.out.println(x == y);//false
}

注意在Integer类中定义了内部类IntegerCache结构,在这个结构中定义了Integer[]保存了-128~127范围内的整数。如果我们使用自动装箱的方式,给Integer在-128至127之间赋值时可以直接使用数组中的元素,不用再去new一个新的元素。

本节练习

ex1

JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第5张图片

public class InstanceTest {
	public static void main(String[] args) {
		InstanceTest t1 = new InstanceTest();
		t1.method(new Person());
		System.out.println();
		t1.method(new Student());
		System.out.println();
		t1.method(new Graduate());
	}
	
	public void method(Person e) {
		System.out.println(e.getInfo());	
		if(e instanceof Graduate) {
			System.out.println("a graduate , student, person");
		}else if(e instanceof Student) {
			System.out.println("a student, person");
		}else {
			System.out.println("a person");
		}
	}
}

class Person{
	 protected String name="person"; 
	 protected int age=50; 
	 public String getInfo() { 
		 return "Name: "+ name + ", " +"age: "+ age; 
	} 
}

class Student extends Person{
	 protected String school="pku"; 
	 public String getInfo() {
		 return  "Name: "+ name + ", age: "+ age 
				 + ", school: "+ school;
	} 
}

class Graduate extends Student{
	public String major="IT";
	public String getInfo(){
		return  "Name: "+ name + ", age: "+ age 
				+ ", school: "+ school+", major:"+major; 
		} 
}

ex2

JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第6张图片
GeometricObject.java:

public class GeometricObject {
	String color;
	double weight;
	
	public GeometricObject(String color, double weight) {
		this.color = color;
		this.weight = weight;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public double getWeight() {
		return weight;
	}

	public void setWeight(double weight) {
		this.weight = weight;
	}
	
	public double findArea() {
		return 0.0;
	}
}

Circle.java:

public class Circle extends GeometricObject {

	private double radius;
	
	public Circle(String color, double weight, double radius) {
		super(color, weight);
		this.radius = radius;
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}
	
	@Override
	public double findArea() {
		return Math.PI*radius * radius;
	}
}

MyRectangle.java:

public class MyRectangle extends GeometricObject{
	private double	width;
	private double height;

	public MyRectangle(double width, double height,String color, double weight) {
		super(color, weight);
		// TODO Auto-generated constructor stub
		this.width = width;
		this.height = height;
	}

	public double getWidth() {
		return width;
	}

	public void setWidth(double width) {
		this.width = width;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}
	
	@Override
	public double findArea() {
		return width * height;
	}
}

GeometricTest.java:

public class GeometricTest {
	public static void main(String[] args) {
		GeometricObject g1 = new Circle("red",1,1);
		GeometricObject g2 = new Circle("red",1,1);
		GeometricObject g3 = new MyRectangle(2,3,"red",1);
		GeometricObject g4 = new MyRectangle(3,2,"red",1);
		GeometricTest t = new GeometricTest();
		
		t.displayGeometricObject(g1);
		t.displayGeometricObject(g2);
		t.displayGeometricObject(g3);
		t.displayGeometricObject(g4);
		if(t.equalsArea(g3, g4)) {
			System.out.println("g3 g4 面积相等");
		}else {
			System.out.println("g3 g4 面积不等");
		}
		
		if(t.equalsArea(g3, g2)) {
			System.out.println("g3 g2 面积相等");
		}else {
			System.out.println("g3 g2 面积不等");
		}
	}
	
	public boolean equalsArea(GeometricObject g1, GeometricObject g2) {		
		return g1.findArea() == g2.findArea();
	}
	
	public void displayGeometricObject(GeometricObject g) {
		System.out.println("图形的面积为:" + g.findArea()); 
	}
}

ex3

JAVA基础学习笔记(7):多态、Object类、单元测试、包装类_第7张图片
Order.java:

public class Order {
	int orderId;
	String orderName;
	
	public Order() {
		super();
	}

	public Order(int orderId, String orderName) {
		super();
		this.orderId = orderId;
		this.orderName = orderName;
	}

	public int getOrderId() {
		return orderId;
	}

	public void setOrderId(int orderId) {
		this.orderId = orderId;
	}

	public String getOrderName() {
		return orderName;
	}

	public void setOrderName(String orderName) {
		this.orderName = orderName;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		if(obj instanceof Order) {
			Order ord = (Order)obj;
			return this.orderId == ord.orderId && this.orderName.equals(ord.orderName);
		}else {
			return false;
		}
	}
}

OrderTest.java:

public class OrderTest {
	public static void main(String[] args) {
		Order o1 = new Order(1,"abc");
		Order o2 = new Order(1,"abc");
		System.out.println(o1.equals(o2));
	}
}

参考资料:
[1]尚硅谷宋康红java基础教程

你可能感兴趣的:(java基础)