对象 Object
OOP特征二: 继承性(inheritance)
class className1 extends ClassName2 {}: className1 继承了 className2 的属性和方法
继承性的好处:
-
减少代码冗余,提高了代码的复用性
-
便于功能的扩展
-
为之后多态性的使用,提供了前提
继承性的格式: class A extends B {}
-
A: 子类、subclass
-
B: 父类、superclass
-
子类继承父类后,可以声明自己的属性和方法
体现: 一旦子类A继承父类B后,子类A就获取了父类B中的结构: (所有的)属性和方法
特别的: 父类中声明为 private 的属性或方法,子类继承父类后,仍然认为获取到了父类中的私有属性或方法,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
public class Person {
String name;
private int age;
public Person () {}
public int getAge () {
return age;
}
public void setAge (int age) {
this.age = age;
}
public void eat () {
System.out.println("eat");
}
public void sleep () {
System.out.println("sleep");
}
}
public class Student extends Person {
// String name;
// int age;
String major;
public Student () {}
public Student (String name, int age, String major) {
this.name = name;
this.age = age;
this.major = major;
}
// public void eat () {
// System.out.println("eat");
// }
// public void sleep () {
// System.out.println("sleep");
// }
public void study () {
System.out.println("study");
}
// Student 中不能直接使用 age 属性
public void show () {
System.out.println("name: " + name + "age: " + getAge());
}
}
public class extendsTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.age = 1;
p1.eat(); // eat
Student s1 = new Student();
s1.name = "Jerry";
s1.eat(); //
s1.sleep();
s1.study();
s1.setAge(10);
s1.getAge(); // 10
}
}
Java中关于继承性的规定
-
Java 只支持单继承和多层继承,不允许多重继承
- 单继承性, 一个子类只能有一个父类
- 一个父类可以派生多个子类
- 多层继承,子父类是相对概念
-
子类继承父类后,就获取了直接父类以及所有间接父类中声明的属性和方法
如果没有显式声明一个类的父类的话,则此类继承于java.lang.Object 类
- 所有的 java类,都直接或间接继承于 java.lang.Object 类
总结:
继承性
继承性的优点
-
减少代码冗余,提高代码复用性
-
便于功能扩展
-
为之后多态性的使用,提供了前提
继承的格式: class A extends B {}
子类继承父类后的特点
-
一旦子类A 继承了父类B 后,子类A 就全部继承了父类B 的属性和方法
-
子类可以根据需要创建自己的属性和方法
-
子类中继承父类的属性和方法,仍然受其权限控制符的影响(封装性)
-
所有的 Java类,都直接或间接继承于 java.lang.Object类(根父类)
方法的重写(override)
定义
在子类中可以根据需要对从父类中继承的方法进行改造,也称为方法的重置、覆盖; 在程序执行时,子类的方法将覆盖父类的方法。
要求
-
子类重写的方法必须和父类被重写的方法具有相同的 方法名、参数列表
-
子类重写的方法返回值类型
不大于父类被重写的方法的返回值类型- 父类 void : 子类 void
- 父类 A类 : 子类 A类或A类的子类 (Object : Object或String Array...)
- 父类 基本数据类型 : 子类 相对应的基本数据类型 (double : 只能是double)
- 子类重写的方法抛出的异常的类型 不大于 父类被重写的 (Exception : Exception或RuntimedException)
-
子类重写的方法使用的访问权限
不小于父类被重写的方法的访问权限 -
特殊情况: 子类不能重写父类中声明为
private权限的方法 -
子类方法抛出的异常类型
不大于父类被重写方法抛出的异常类型
注意
子类与父类中同名同参数的方法必须同时声明为非static的(可以考虑重写),或者同时声明为static的(不是重写);
因为static是属于类的,子类无法覆盖父类的方法。
四种访问权限修饰符
protected
在不同包的子类中,不能调用 Order类 中声明为 private 和 缺省 权限的属性、方法
./code/java1
public class Order {
private int i;
String str;
protected int age;
public String addr;
int getAge () {
return age;
}
protected String getStr () {
return str;
}
}
./code/java2
import code.java1.Order;
public class SubOrder extends Order {
public void method () {
i = 10;
age = 12;
// getAge(); error 权限不够
getStr();
}
}
关键字: super
主要解决
子父类属性、方法冲突的问题
super 关键字的使用
-
super 理解为: 父类的...
-
super 可以用来调用: 属性、方法、构造器
-
我们在子类的方法和构造器中,通过使用
super.属性、super.方法的方式,显示的调用父类中声明的属性和方法;但是一般可以省略 -
属性-特殊情况: 当父类和子类中定义了同名的属性时,如果要在子类中使用父类中的属性和方法,必须显示的使用
super.属性、super.方法表明使用的是父类中的属性和方法 -
方法-特殊情况: 当子类重写了父类的方法后,可以使用
super.方法指定调用父类中被重写的方法 -
构造器: 我们可以在子类的构造器中显示的使用
super(参数列表)的方式,调用父类中声明的指定的构造器;-
super(参数列表)的使用,必须声明在子类构造器的首行,所以this(参数列表)和super(参数列表)在类的构造器中只能二选一 -
在子类的构造器中,没有显示使用
this(参数列表)或super(参数列表)的情况下,默认使用super()调用父类中的 空参构造器 -
在类的多个构造器中,至少有一个类的构造器中使用了
super()调用父类中的构造器
-
public class Person {
String name;
int age;
String id = 10001; // 身份证
public Person () {}
public Person (String name) {
this.name = name;
}
public Person (Sring name, int age) {
this(name);
this.age = age;
}
public void eat () {
System.out.println("eat");
}
public void walk () {
System.out.println("walk");
}
}
public class Student extends Person {
String major;
String id = 1002; // 学号
public Student () {}
public Student (String major) {
this.major = major;
}
public Student (String name, int age, String major) {
super(name, age); // 调用父类构造器
this.major = major;
}
public void eat () {
System.out.println("student eat much !");
}
public void show () {
System.out.println("name: " + name + ", age: " + age);
System.out.println("this.id: " + id); // 子类 学号
System.out.println("super.id" + super.id); // 父类 身份证
this.eat(); // 子类eat
super.eat(); // 父类eat
}
}
public class SuperTest {
public static void main(String[] args) {
Student s1 = new Student();
s1.show();
Student s2 = new Student('lv', 22, 'computer');
}
}
子类对象实例化过程
从结果上来看
-
子类继承了父类以后,就获取了父类中声明的属性或方法
-
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性和方法
从过程上来看
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接调用其父类的构造器,进而调用父类的父类的构造器,...,直到调用了 java.lang.Object类中空参构造器为止。
正因为子类加载过所有父类的构造器,所以,我们才能将父类中的属性和方法加载到内存中,从而子类的对象才可以考虑进行调用
明确: 虽然在创建子类对象时,调用了父类的构造器,但自始至终就只创建了一个对象,即为当前 new 的子类对象
OOP特征三: 多态性
多态性(适用于方法)
多态性,是面向对象中最重要的概念,
只适用于方法不适用于属性,在Java中的体现:
-
对象的多态性:
父类的引用指向子类的对象(子类的对象赋给父类的引用)- 可以直接应用在抽象类和接口上
- 格式:
父类 变量 = new 子类();
Java引用变量有两个类型: 编译时类型和运行时类型;编译时类型由声明时该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定;简称: 编译时,看左边、运行时,看右边。
-
若编译时类型和运行时类型不一致,就出现了对象的多态性
-
多态情况下(只适用于方法):
- 看左边: 看的是父类的引用(父类中不具备子类特有的方法)
- 看右边: 看的是子类的对象(实际运行的是子类重写父类的方法)
-
多态是
运行时行为
多态的使用
当调用子父类同名参数的方法时,实际执行的是子类重写父类的方法 -- 虚拟方法调用
-
有了对象的多态性后,我们在编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类的方法
-
总结: 编译,看左边;运行,看右边
-
使用前提:-
要有类的继承关系
-
子类中要有父类方法的重写
-
public class Person {
int age;
String name;
public void eat () {
System.out.println("eat");
}
public void walk () {
System.out.println("walk");
}
}
public class Man extends Person {
boolean isSmoke;
public void eat () {
System.out.println("Man eat much!");
}
public void strong () {
System.out.println("Man is very Strong!");
}
}
puvlic class Woman extends Person {
boolean isBeauty;
public void eat () {
System.out.println("Woman eat less!");
}
}
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Man();
p1.eat(); // Man eat much!
// p1.strong(); 编译报错,Person中没有此方法
}
}
多态性使用实例
public class AnimalTest {
public static void main(String[] args) {
AnimalTest t1 = new AnimalTest();
t1.fun(new Dog()); // Dog类
t1.fun(new Cat()); // Cat类
}
// public void fun (Dog a1) {
// public void fun (Cat a1) {
public void fun (Animal a1) {
// Animal a1 = new Dog();
a1.eat();
a1.shout();
}
}
class Animal {
public void eat () {
System.out.println("eat");
}
public void shout () {
System.out.println("shout");
}
}
class Dog extends Animal {
public void eat () {
System.out.println("dog eat!");
}
public void shout () {
System.out.println("dog shout!");
}
}
class Cat extends Animal {
public void eat () {
System.out.println("cat eat!");
}
public void shout () {
System.out.println("cat shout!");
}
}
// 数据库操作
class Driver {
public void doData (Connection con) {
// con = new MySql()
// con = new Oracle()
// Java规范步骤去操作数据
con.method1();
con.method2();
con.method3();
}
}
多态性扩展: instanceof 操作符
instanceof的使用:
a instanceof A; 判断对象a 是否是类A的实例,返回值为 true、false
-
为了在向下强转之前不出现异常,需要在强转之前进行判断
-
如 a instanceof A 返回true,且 a instanceof B 也返回true,则 B是A的父类
if (p1 instanceof Woman) {
Woman w1 = (Woman)p1;
w1.goShopping();
} else if (p1 instanceof Man) {
Man m1 = (Man)p1;
m1.earnMoney();
}
向下转型
有了对象的多态性后,内存中实际上是加载了子类特有的属性和方法 ,但由于变量声明为父类,导致在编译时,只能调用父类中声明的属性和方法;子类特有的属性和方法不能调用
如何解决调用子类特有属性和方法的问题:
-
Person p1 = new Man();
-
使用向下转型: 强制类型转换符 Man m1 = (Man)p1; 可能会转换失败,比如Woman w1 = (Woman)p1; error: ClassCastException;为避免出错引入关键字: instanceof
-
int -> double (自动类型提升);double -> int (强制类型转换)
-
子类 -> 父类 (向上转型,多态);父类 -> 子类 (向下转型,instanceof判断)
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 MethodTest {
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(p == s); // true
System.out.println(b.count); // 10
b.display(); // 20
}
}
总结:
-
若子类重写父类的方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转义到子类中;编译看左边,运行看右边
-
对于
实例的变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例 变量,这个实例的 变量依然不可能覆盖父类中定义的实例变量;编译运行都看左边。
常出现的问题 Error
编译通过,运行不通过
Person p1 = new Woman();
Man m1 = (Man)p1; // error: ClassCastException
Person p2 = new Person();
Man m2 = (Man)p2; // error
编译通过,运行时也通过
Object o1 = new Woman();
Person p1 = (Person)o1;
Person p2 = new Man();
Man m2 = (Man) p2; // 此用法在 Servlet中的 service方法应用
编译不过(
不相关的两个类是不可以赋值的)
Man m1 = new Woman(); // error: type of miss match
String s1 = new Date(); // error
Object o1 = new Date();
String s1 = (String)o1; // error
test
public class InterviewTest {
public static void main(String[] args) {
Base b1 = new Sub();
b1.add(1, 2, 3); // sub_1: 多态性
Sub s1 = (Sub)b1;
s1.add(1, 2, 3); // sub_2: 优先执行参数确定的方法
}
}
class Base {
public void add (int a, int... arr) {
System.out.println("base");
}
}
class Sub extends Base {
public void add (int a, int[] arr) {
System.out.println("sub_1");
}
public void add (int a, int b, int c) {
System.out.println("sub_2");
}
}
小结
方法的重载与重写
概念
重载: 在同一个类中可以同时声明多个方法名相同但参数列表不同的方法,彼此之间就构成了重载,构造器也可以重载
重写: 子类继承父类后,可以对父类中同名同参数的方法进行覆盖操作
从编译运行的角度看
重载,指类中允许存在多个同名方法,而这些方法的参数不同;编译器根据方法不同的参数表,对同名方法的名称做修饰,对编译器而言,这些同名方法就成了不同的方法;它们的调用地址在编译器就绑定了,这称为早绑定、静态绑定
多态,只能等到方法调用的那一刻,解释器运行器才会确定所要调用的具体方法,这称为晚绑定、动态绑定
引用一句Bruce Ecke: 不要犯傻,如果它不是晚绑定,它就不是多态
多态性、虚拟方法调用
-
多态性: 父类的引用指向子类的对象
-
虚拟方法调用: 当我们调用子父类中同名同参的方法时,编译时认为是调用父类中的方法,解释运行时认为调用是子类中的方法
方法重写的具体规则非static问题
-
方法名、形参列表相同
-
子类的权限修饰符不能小于父类
-
返回值类型
-
子类抛出的异常不能大于父类的异常
-
开发中建议复制粘贴
super调用构造器具体的注意点
-
this(形参列表): 本类中重载的其它构造器
-
super(形参列表): 调用父类中指定的构造器
-
this和super都只能写在构造器的首行,两者只能二选一
-
在构造器中默认调用 super() 空参
-
在一个类的多个构造器中最多出现 n-1个this,最少有一个super
-
在创建一个子类对象时,一定会调用其父类们的构造器
-
super或this调用语句只能作为构造器中的第一行出现
子类中,无论哪个构造器创建子类对象,需要先保证初始化父类;目的是: 当子类继承父类后,继承父类中所有的属性和方法,因此子类有必要知道父类如何为对象进行初始化(先明确父类如何做);所以对象中加载的父类的属性顺序: java.lang.Object > 间接父类... > 直接父类 > 本类
Java如果没有多态性那抽象类和接口毫无意义
- 抽象类和接口不能创建对象,所以只能通过子类继承的方式
Object类的使用
-
Object类是所有Java类的根父类
-
如果在类的声明中未使用extends关键字指明其父类,默认直接父类是java.lang.Object类
Object类中的功能
-
equals(): 比较两个对象是否相等
-
toString(): 返回类名和其引用地址
-
getClass: 获取当前对象的所属类
-
hashCode(): 返回当前对象的hash值
-
clone(): 返回对象的复制体
-
finalize(): 对象在被销毁之前会调用对象中的finalize方法
-
wait()
-
notify()
== 和 equals 的异同
-
== 既可以比较基本数据类型页可以比较引用数据类型;对于基本数据类型比较的是数据值,对于引用数据类型比较的是内存地址值
-
equals()的话,它属于java.lang.Object类中的方法,如果该方法没有被重写,默认就是
==;我们可以看到 String等类的equals方法是被重写过的,而String类在日常开发中用的比较多,就形成了equals是比较值的错误观点 -
具体要看自定义类是否重写Object的equals()方法来判断
-
通常情况下,重写equals()方法,会比较类中相应的属性是否相等
-
基本数据类型使用
==,引用数据类型使用 equals()
-
==运算符 的使用:
-
可以使用在基本数据类型变量和引用数据类型变量中
-
如果比较的是基本数据类型变量: 比较两个变量保存的数据是否相等(类型可能不同)
-
如果比较的是引用数据类型变量: 比较两个对象的地址值是否相等
-
-
equals()方法的使用:
-
是一个方法,而非运算符
-
不能使用在 基本数据类型 变量中,只能适用于引用数据类型
-
Object类中 equals() 的定义: 和 == 的作用是相同的
public boolean equals (Object obj) { return (this == obj) }
-
像 String、Date、File、包装类等,都重写了Object类中的equals()方法,比较的是两个对象的 ‘实体内容’ 是否相等
-
自定义类如何重写 equals() 方法
int i = 10; int j = 10; double m = 10.0; System.out.println(i == m); // true(自动类型提升) char c = 10; System.out.println(c == i); // true char c1 = 'A'; char c2 = 65; System.out.println(c1 == c2); // true // equals Customer c1 = new Customer("Tom", 21); Customer c2 = new Customer("Tom", 21); String s1 = new String("atjava"); String s1 = new String("atjava"); System.out.println(c1.equals(c2)); // false true(override) System.out.println(s1 == s2); // false(地址不同) System.out.println(s1.equals(s2)); // true(override) public class Customer { String name; int age; public boolean equals (Object obj) { if (this == obj) { return true; } if (obj instanceof Customer) { Customer cust = (Customer)obj; // 比较两个对象的属性是否都相同 if (this.name == cust.name && this.name.equals(cust.name)) { return true; } } return false; } } -
包装类(wrapper)的使用
概念介绍
-
针对八种基本数据类型定义相应的引用类型 - 包装类(封装类)
-
有了类的特点,就可以调用类中的方法,Java才是真正的面向对象
- byte - Byte
- short - Short
- int - Integer
- long - Long
- float - Float
- double - Double
- boolean - Boolean
- char - Character
说明: 以上数值类型的包装类中其直接父类是 Number类
核心: 基本数据类型、包装类、String 三者之间的转化
- 新特性: JDK 5.0 自动装箱与拆箱 -> 直接赋值
import org.junit.Test;
public class WrapperTest {
// 1. 基本数据类型 -> 包装类: 调用包装类的构造器
@Test
public void test1 () {
int i1 = 10;
Integer i11 = new Integer(i1);
System.out.println(i11.toString()); // 10
Integer i22 = new Integer("112");
System.out.println(i22.toString()); // 123
// Float f11 = new Float(12.33); // double
// Float f11 = new Float("12.33");
Float f11 = new Float(12.33f);
System.out.println(f11.toString());
Boolean b11 = new Boolean(true);
Boolean b12 = new Boolean("true"); // true
Boolean b12 = new Boolean("TruE"); // true
Boolean b13 = new Boolean("true123"); // false
Person p1 = new Person();
System.out.println(p1.isMale); // false
System.out.println(p1.isFemale); // null
}
// 2. 包装类 -> 基本数据类型: 调用包装类的 xxxValue()
@Test
public void test2 {
Integer i1 = new Integer(13);
int i11 = i1.intValue();
Float f1 = new Float(12.5);
float f11 = f1.floatValue();
}
@Test
public void test3 () {
int n1 = 10;
// 基本数据类型 -> 包装类
Integer i1 = new Integer(n1);
method(i1);
int n2 = 16;
// JDK 5.0 自动装箱与拆箱 - *****
// 自动装箱
Integer i2 = n2;
boolean b1 = true;
Boolean b11 = b1; // 自动装箱
// 自动拆箱
int n3 = i2;
}
public void method (Object obj) {
System.out.println(obj.intValue());
}
// 3. 基本数据类型、包装类 -> String类型: 调用String重载的valueOf(Xxx xxx)
public void test3 () {
int n1 = 10;
// 连接运算
String s1 = n1 + "";
// 调用String的valueOf() - *****
float f1 = 123.45f;
String s2 = String.valueOf(f1); // "123.45"
Double d1 = new Double(45.6);
String s3 = String.valueOf(d1); // "45.6"
}
// 4. String类型 -> 基本数据类型、包装类: 调用包装类的parseXxx()
@Test
public void test4 () {
String s1 = "79";
// parseXxx() - *******
int i1 = Integer.parseInt(s1); // 79
String s2 = "true";
boolean b1 = Boolean.parseBoolean(s2); // true
String s3 = "true123";
boolean b1 = Boolean.parseBoolean(s3); // false
}
}
class Person {
boolean isMale;
Boolean isFemale;
}
public class InterviewTest {
@Test
public void test1 () {
// 三元运算符要求类型统一
Object o1 = true ? 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 test1 () {
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 = 123; // 相当于 new Integer(128) 对象
Integer y = 123;
System.out.println(x == y); // false
}
}
包装类实际应用
import java.util.Scanner;
import java.util.Vector;
public class ScoreTest {
public static void main (String[] args) {
// instance Scanner
Scanner scan = new Scanner(System.in);
// instance Vector obj
Vector v = new Vector();
// loop Vector
int maxScore = 0;
for (;;) {
System.out.print("please input student score: ");
int score = scan.nextInt();
if (score < 0) {
System.out.println("Exit !");
break;
} else if (score > 100) {
System.out.println("please again input num !");
continue;
}
// jdk 5.0 before
// Integer inScore = new Integer(score);
// v.addElement(inScore); // many atitude
// jdk 5.0 after
v.addElement(score); // // auto pack
if (maxScore < score) {
maxScore = score;
}
}
// add obj
// Exit -num
// get max score
// loop Vector get A B C ...
char level;
for (int i = 0; i < v.size(); i++) {
Object obj = v.elementAt(i);
// jdk 5.0 before
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
// jdk 5.0 after
// int score = (Integer)obj; // auto unpack
int score = (int)obj;
if (maxScore - score <= 10) {
level = 'A';
} else if (maxScore - score <= 20) {
level = 'B';
} else if (maxScore - score <= 30) {
level = 'C';
} else {
level = 'D';
}
System.out.println("student - " + i + " score is " + score + " level is " + level);
}
}
}
小结
如何实现向下转型?需要注意的问题?如何解决此问题?
-
使用强转符: (), Person p1 = new Man(); Man m1 = (Man)p1;
-
使用instanceof在向下转型前进行判断,
if (p1 instanceof Man) { Man m1 = (Man)p1; }
== 和 equals() 的区别
-
== 可以比较基本数据类型和引用数据类型
-
equals() 只能应用在引用数据类型中,比较两个对象是否相等
- 如果没有重写equals()方法的话,比较的是对象的地址
- 一般重写的eqauls()方法,比较的是存储的内容
重写equals()方法
class User {
String name;
int age;
// 简写版
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof User) {
User u1 = (User)obj;
return this.age == u1.age && this.name.equals(u.name);
}
return false;
}
// 生成版
public boolean equals (Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Person p1 = (Person)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;
}
}
写出8种基本数据类型及其对应包装类
- int : Integer
- byte : Byte
- short : Short
- long : Long
- char : Character
- float : Float
- double : Double
基本数据类型、包装类与String三者如何转换
-
基本数据类型 -> 包装类
- 自动装箱 Integer i1 = 12;
- 自动拆箱 int i11 = i1;
-
基本数据和包装类 -> String
- 转为String类型: String.valueOf(Xxx xxx);
- 转为包装类: Xxx.parseXxx(String str);
toString()方法
-
当我们输出一个对象的引用时,实际是在调用当前对象的toString()方法
-
Object类中toString()的定义:
public String toString () { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } -
像String、Date、File、包装类等重写了Object类中的toString()方法,使得在调用对象的toString()时,返回
实体内容信息 -
重写toString()
public String toString () { return "Customer [name= " + name + " , age= " + age + "]"; }
JUnit单元测试
步骤
-
选中当前工程 - 右键选择: build path - add libraries - JUnit 4 - 下一步
-
创建一个java类,进行单元测试
-
要求: 此类是public的、提供一个public无参的构造器
-
在此类中声明单元测试方法: 方法权限是public、无返回值、无形参
-
此单元测试方法上需要声明注释: @Test,并在单元测试类中导入 org.junit.Test
-
写完代码后,左键双击单元测试方法名,右键: run as - JUnit Test
-
执行结果无异常: 绿条,反之,红条
实例
import org.junit.Test;
public class JUnitTest {
int num = 10;
@Test
public void testEquals () { // 非静态
String s1 = "MM";
String s2 = "MM";
System.out.println(s1.equals(s2));
// main()方法是静态的必须要造对象
System.out.println("num: " + num);
show();
}
public void show () {
System.out.println("show");
}
@Test
public void testToString () {
String s3 = "MM";
System.out.println(s3.toString());
}
}
复习
向下转型和向上转型
向上转型: 多态
向下转型:
- 为何使用向下转型:
有了对象的多态性后,内存中实际上加载了子类特有的属性和方法,但因为声明为父类类型,导致编译时,只能调用父类中声明的属性和方法,无法调用子类特有的属性和方法,使用向下转型可以解决此问题
-
如何实现向下转型: ()
-
注意点:
- instanceof判断
多态性的理解
主要目的: 尽可能实现代码的通用性
-
Object类中定义的 public boolean equals(Object obj){} 方法
-
JDBC: 使用java程序操作(获取数据库连接、CRUD)数据库(MySql、Oracle...)
-
抽象类、接口的使用肯定体现了多态性(没有多态性就没有意义)