instanceof
例一:
person类:
package com.acoffee.exer3;
public class Person {
String name;
int age;
public void eat() {
System.out.println("人:吃饭");
}
public void walk() {
System.out.println("人:走路");
}
}
Man类:
package com.acoffee.exer3;
public class Man extends Person{
boolean isSmoking;
public void earnMonry() {
System.out.println("男人负责挣钱养家");
}
public void eat() {
System.out.println("男人多吃肉,长肌肉");
}
public void walk() {
System.out.println("男人要霸气的走路");
}
}
Woman类:
package com.acoffee.exer3;
public class Woman extends Person {
boolean isBeauty;
public void goShopping() {
System.out.println("女人喜欢购物");
}
public void eat() {
System.out.println("女人少吃要减肥");
}
public void walk() {
System.out.println("女人秀气的走路");
}
}
PersonTest类:
package com.acoffee.exer3;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Man man = new Man();
man.eat();
man.age = 25;
man.earnMonry();
//************************
//对象的多态性:我们声明的是父类 调
//用的是子类的对象。即父类的对象指
//向子类的对象
Person p2 = new Man();
Person p3 = new Woman();
//多态的使用:当调用子父类同名参数的方法是,实际
//执行的是子类重写父类的方法---虚拟方法调用
p2.eat();
p2.walk();
//p2.earnMoney(); 不能调用子类所特有的方法:编译时:p2是Person类型
}
}
有了对象的多态性以后,内存实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的方法不能调用。
我们昨天讲的不能调用子类所特有的方法,但是这种情况应该怎么解决呢?
向下转型:使用强制类型转换符: Man m1 = (man)p2;
Man m1 = (Man)p2;
m1.earnMoney();
m1.isSmoking = true;
这样操作过后我们就可以调用子类锁特有的属性和方法。
使用强转时,可能会报ClassCastException这个类转换异常 因为我们先转换成了Man类型然后在转换成Woman类型不能的所以报了异常,为了我们写程序时去避免这个问题我们就引入关键字instanceof
instanceof 关键字的使用:
要求x所属的类与类A必须是子类和父类(直接或间接)的关系,否则编译错误。
a(变量名) instance of A(类):
判断对象a是否是类A的实例。如果是,返回true:如果不是,返回false。
使用情景:为了避免向下转型是出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就向下转型。如果返回false,不进行向下转型。
如果B是A的父类:
a instance of A返回true, 那么a instance of B也返回true.
我们修改PersonTest类:
package com.acoffee.exer3;
public class PersonTest {
public static void main(String[] args) {
Person p2 = new Man();
if(p2 instanceof Woman) {
Woman w1 = (Woman)p2;
w1.goShopping();
System.out.println("*******Woman*******");
}
if(p2 instanceof Man) {
Man w2 = (Man)p2;
w2.earnMoney();
System.out.println("*******Man*******");
}
}
}
执行结果:
我们发现if(p2 instanceof Man){ }中的代码是执行了的,而if(p2 instanceof Woman){ }中的代码却没有执行,因为我们只Person p2 = new Man();所以if(p2 instanceof Man){ }就能通过,而woman那个就不能通过所以就运行不出来.
应该去new一个叫低级别的类 然后在往上转型。
多态练习:
练习一:
class Base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;//多态性
//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
System.out.println(b == s);//true
System.out.println(b.count);//10
b.display();//20
}
}
-
1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
-
2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边。
练习二:
/*
* 建立InstanceTest 类,在类中定义方法method(Person e);
在method中:
(1)根据e的类型调用相应类的getInfo()方法。
(2)根据e的类型执行:
如果e为Person类的对象,输出:
“a person”;
如果e为Student类的对象,输出:
“a student”
“a person ”
如果e为Graduate类的对象,输出:
“a graduated student”
“a student”
“a person”
*
*
*
*/
public class InstanceTest {
public static void main(String[] args) {
InstanceTest test = new InstanceTest();
test.method(new Student());
}
public void method(Person e){
//虚拟方法调用
String info = e.getInfo();
System.out.println(info);
//方式一
// if(e instanceof Graduate){
// System.out.println("a graduated student");
// System.out.println("a student");
// System.out.println("a person");
// }else if(e instanceof Student){
// System.out.println("a student");
// System.out.println("a person");
// }else{
// System.out.println("a person");
// }
//方式二
if(e instanceof Graduate){
System.out.println("a graduated student");
}
if(e instanceof Student){
System.out.println("a student");
}
if(e instanceof Person){
System.out.println("a person");
}
}
}
class Person {
protected String name = "person";
protected int age = 50;
public String getInfo() {
return "Name: " + name + "\n" + "age: " + age;
}
}
class Student extends Person {
protected String school = "pku";
public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school;
}
}
class Graduate extends Student {
public String major = "IT";
public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school + "\nmajor:" + major;
}
}
object类的使用
Object类中的功能(属性,方法)具有的通用性。
属性:无
方法:equals()/ toString()/ getClass/ hashCode()/ clone()/ finalize()/ wait()/ notify()/ notifyAll()
Object类之声明一个空参构造器
我们下面重点讲equals方法 和 toString方法。
equals
== 和 equals 的区别
一、回顾 == 的使用
==:运算符
1.可以使用在基本数据类型变量和引用数据类型变量中。
2.如果比较的是基本数据变量:比较两个变量保存的数据是否相等。(不一定类型要相等)
3.如果是比较的是引用数据类型变量,比较的是两个地址值是否相同,即两个引用是否指向同一个对象实体。
二、equals方法的使用
1.是一个方法,而非运算符
2. 只能适用于引用数据类型
3. Object类中equals()的定义:
public boolean equals(Object obj){
return (this == obj);
}
说明:在Object类中定义的equals()和 == 的作用是相同的。
4.像String、Data、File、包装类等都重写了Object() 方法。重写以后,比较的不是两个引用的地址是否相同,而是比较的两个对象的“实体内容”是否相同。
举例:
5.通常情况下,我们自定义的类如果使用equals的话,也通常是比较两个对象的“实体内容”是否相同。那么我们就需要对Object类中的equals()进行重写。 可以自动生成。
补充: == 符号使用时, 必须保证付哈左右两边的变量类型保持一致。
练习:
package com.acoffee.exer;
/*
* 编写Order类,有int型的orderId,String型的orderName,
* 相应的 getter()和setter()方法,
* 两个参数的构造器,重写父类的equals()方法:
* public boolean equals(Object obj),
* 并判断测试类中创建的两个对象是否相等。
*/
public class OrderTest {
public static void main(String[] args) {
Order order1 = new Order(1001,"AA");
Order order2 = new Order(1001,"BB");
System.out.println(order1.equals(order2));
Order order3 = new Order(1001,"BB");
System.out.println(order2.equals(order3));
}
}
class Order{
private int orderId;
private String 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;
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
@Override
public boolean equals(Object obj) { //先判断引用地址一不一样
if(this == obj) { //引用地址一样直接返回true
return true;
}
if(obj instanceof Order) {//然后判断这个形参跟我们被判断这个对象
//是不是同一类型,如果类型都不同就返回false,如
//一个String型的去判断,而这个形参不是String类型
//两个就肯定不相同
Order order = (Order)obj; //我们把形参强转
return this.orderId == order.orderId && //orderId是int型,我们直接用==比较
this.orderName.equals(order.orderName);//而orderName是String类型我们直接用equals比较
//我们前面提到equals在String中是已经被重写了
}
return false;
}
}
toString()
Java中的JUnit单元测试
- 步骤:
- 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
- 说明:
- 1.如果执行结果没有任何异常:绿条
- 2.如果执行结果出现异常:红条
public class JUnitTest {
int num = 10;
@Test
public void testEquals(){
String s1 = "MM";
String s2 = "MM";
System.out.println(s1.equals(s2));
//ClassCastException的异常
// Object obj = new String("GG");
// Date date = (Date)obj;
System.out.println(num);
show();
}
public void show(){
num = 20;
System.out.println("show()....");
}
@Test
public void testToString(){
String s2 = "MM";
System.out.println(s2.toString());
}
}
包装类的使用(Wrapper)
练习:
基本数据类型→包装类
package com.acoffee.java1;
import org.junit.Test;
public class WrapperTest {
//基本数据类型→包装类:调用包装类的构造器
@Test
public void test1() {
int num1 = 10;
//这种表达方式是错误的num1是基本数据类型不能去调方法
// System.out.println(num1.toString());
Integer in1 = new Integer(num1);
System.out.println(in1.toString());
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型 忽略大小写只要是true就输出true,不然就是flase
Boolean b1 = new Boolean("true");
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);//true
Boolean b3 = new Boolean("123abc");
System.out.println(b3);//false
Order order = new Order();
System.out.println(order.isMale);//false
//因为现在isFemale是一个类了
System.out.println(order.isFemale);//null
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
包装类→基本数据类型:调用包装类的xxxValue()
package com.acoffee.java1;
import org.junit.Test;
public class WrapperTest2 {
//包装类→基本数据类型:调用包装类的xxxValue()
@Test
public void test2() {
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);//13
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.println(f2 + 1);//13.3
}
}
自动拆箱、自动装箱
//JDK5.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)
package com.acoffee.java1;
import org.junit.Test;
public class wrapperTest3 {
//基本数据类型、包装类→String类型:调用String常在的valueof(xxx xxx)
@Test
public void test4() {
int num1 = 10;
//方式一:连接运算
String str1 = num1 + "";
System.out.println(str1);//"10"
//方式二:调用String.valueOf(xxx xxx)
int num2 = 20;
String str2 = String.valueOf(num2);
System.out.println(str2);//"20"
float num3 = 12.3f;
String str3 = String.valueOf(num3);
System.out.println(num3);//"12.3"
Double d1 = new Double(12.4);
String str4 = String.valueOf(d1);
System.out.println(d1);//"12.4"
}
}
//String类型→基本数据类型、包装型:调用包装类xxxx.parsexxx(String s)
package com.acoffee.java1;
import org.junit.Test;
public class WrapperTest4 {
//String类型→基本数据类型、包装型:调用包装类xxxx.parsexxx(String s)
@Test
public void test4() {
String str1 = "123";
int num1 = Integer.parseInt(str1);
System.out.println(num1 + 1);//124
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);//false
}
}
练习题:
面试题:
package com.acoffee.java1;
import org.junit.Test;
public class WrapperTest5 {
@Test
public void test1() {
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);//1.0 因为这里会将所有代码都运行
//一遍所以当运行到Double(2.0)时,前面的int就会类型自动提升为Double型.
}
@Test
public void test2() {
Object o2;
if(true) {
o2 = new Integer(1);
}else {
o2 = new Double(2.0);
}
System.out.println(o2);//1
}
}
面试题2:
@Test
public void test3() {
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;//相当于new了一个Integer对象
Integer y = 128;//相当于new了一个Integer对象
System.out.println(x == y);//false
}
原因:
Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128 到 127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率。
综合练习:
public class ScoreTest {
public static void main(String[] args) {
//1.实例化Scanner,用于从键盘获取学生成绩
Scanner scan = new Scanner(System.in);
//2.创建Vector对象,Vector v=new Vector();相当于原来的数组
Vector v=new Vector();
//3.通过for(;;)或while(true)方式,给Vecotr中添加数组
int maxScore = 0;
for(;;) {
System.out.print("请输入你要读入的成绩(以输入负数表示结束):");
int score = scan.nextInt();
//3.2 当输入时负数时,跳出循环
if(score < 0) {
break;
}
if(score > 100) {
System.out.println("输入错误,请重新输入");
continue;
}
//3.1 添加操作:v.addElement(Object obj);
//JDK5.0之前:(自动装箱)
// Integer inScore = new Integer(score);
// v.addElement(inScore);
v.addElement(score);//自动装箱
//4.获取成绩的最大值
if(score > maxScore) {
maxScore = score;
}
}
//5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的成绩。
char level;
for(int i = 0;i < v.size();i++) {
Object obj = v.elementAt(i);
//在JDK5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
int score = (Integer)obj;
if(maxScore - 10 < score ) {
level = 'A';
}else if(maxScore - 20 < score ){
level = 'B';
}else if(maxScore - 30 < score ){
level = 'C';
}else {
level = 'D';
}
System.out.println("student - " + i + "score is "+ score+",level is "+level);
}
}
}
每日一练:
1.如何实现向下转型?需要注意什么问题?如何解决此问题?
Person p = new Man();
使用强转符:()
Man m = (Man)p;
可能ClassCastException异常。
使用instanceof在进行向下转型前判断。
if(p instanceof Man){
Man m = (Man)p;
}
2.== 和 equals()有何区别?
3.重写equals
class User{
String name;
int age;
//重写其equals()方法
public boolean equals(Object obj){
if(obj == this){
return true;
}
if(obj instanceof User){
User u = (User)obj;
return this.age == u.age && this.name.equals(u.name);
}
return false;
}
}
4. 写出8种基本数据类型及其对应的包装类
int Integer
char Character
5. 基本数据类型、包装类与String三者之间如何转换
自动装箱、自动拆箱
Integer i = 10;
基本数据类型、包装类—>String: valueOf(Xxx xx)
String—>基本数据类型、包装类:parseXxx(String s)