目录
01 面向对象特征之二:继承性
1.1 继承性的使用与理解
Person 类
/*
* 为描述和处理个人信息,定义类 Person
*/
public class Person {
String name; // 缺省
private int age;
// 构造器
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
// 方法
public void eat(){
System.out.println("吃饭");
sleep();
}
private void sleep(){
System.out.println("睡觉");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
构造Student类继承Person类
/*
* 为描述和处理学生信息,定义类 Student
*/
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; // 私有属性由于封装性不能在子类直接调用
setAge(age);
this.major = major;
}
// public void eat(){
// System.out.println("吃饭");
// }
//
// public void sleep(){
// System.out.println("睡觉");
// }
public void study(){
System.out.println("学习");
}
public void show(){
System.out.println("name:" + name + ",age = " + getAge());
}
}
说明
- 为什么要有继承?
- 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,
- 那么多个类无需再定义这些属性和行为,只要继承那个类即可。
- 一、继承性的好处
- 减少了代码的冗余,提高了代码的复用性;
- 便于功能的扩展;
- 为之后多态性的使用,提供了前提。
- 二、继承性的格式
- class A extends B{}
- A:子类、派生类、subclass
- B:父类、超类、基类、superclass
- class A extends B{}
2.1 体现:一旦子类 A 继承父类以后,子类 A 中就获取了父类 B 中声明的结构:属性、方法
- * 特别的,父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
* 只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
2.2 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
子类和父类的关系:不同于子集与集合的关系。
extends:延展、扩展
测试继承
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
// p1.age = 1;
p1.eat();
System.out.println("********************");
Student s1 = new Student();
s1.eat();
// s1.sleep();
s1.name = "Tom";
s1.setAge(10);
System.out.println(s1.getAge());
}
}
1.2 继承的练习
定义manKind类
/*
* 定义一个ManKind类,包括
* 成员变量int sex和int salary;
* 方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0);
* 方法void employeed():根据salary的值显示“no job”(salary==0)或者“job”(salary!=0)。
*
*/
public class ManKind {
private int sex; //性别
private int salary; //薪资
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman(){
if(sex==1){
System.out.println("man");
}else if(sex==0){
System.out.println("woman");
}
}
public void employeed(){
if(salary==0){
System.out.println("no job");
}else if(salary!=0){
System.out.println("job");
}
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
定义kids 继承manKind
/*
* 定义类Kids继承ManKind,并包括
* 成员变量int yearsOld;
* 方法printAge()打印yearsOld的值
*
*/
public class Kids extends ManKind{
private int yearsOld; //年限
public Kids() {
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge(){
System.out.println("I am " + yearsOld);
}
}
测试类kidtests
/*
* 定义类KidsTest,在类的main方法中实例化Kids的对象someKid,
* 用该对象访问其父类的成员变量及方法。
*
*/
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setYearsOld(15); // 通过调用方法来获取信息
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
02 方法的重写(override)
在子类中可以根据需要对从父类中继承来的方法进行改造 也称为方法 的 重置、覆盖 。在程序执行时,子类的方法将覆盖父类的方法。
返回值类型:
* > 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void;
* > 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类;
* > 父类被重写的方法的返回值类型如果是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须是:double)。
*
* ④ 子类方法抛出的异常不能大于父类被重写的方法抛出的异常;
Person 类
public class Person {
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃饭");
}
public void walk(int distance){
System.out.println("走路,走的距离是:" + distance + "公里");
show();
}
private void show(){
System.out.println("我是一个人。");
}
public Object info(){
return null;
}
public double info1(){
return 1.0;
}
}
Student类
public class Student extends Person{
String major;
public Student(){
}
public Student(String major){
this.major = major;
}
public void study(){
System.out.println("学习,专业是:" + major);
}
//对父类中的eat()进行了重写
public void eat(){
System.out.println("学生应该多吃有营养的。");
}
public void show(){
System.out.println("我是一个学生。");
}
public String info(){
return null;
}
// public int info1(){ // 重写必须与父类同类型
// return 1;
// }
//可以直接将父类的方法的第一行粘过来,直接写方法体
@Override
public void walk(int distance) {
System.out.println("自动生成");
}
}
测试
public class PersonTest {
public static void main(String[] args) {
Student s = new Student("计算机科学与技术");
s.eat(); // 学生应该吃好点
s.walk(10);
s.study();
}
}
03 四种访问权限修饰符
访问控制举例
order类
package OOP_Zhong;
public class Order {
private int orderPrivate; //private
int orderDefault; // default
protected int orderProtected; // protected
public int orderPublic; // public
private void methodPrivate(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
void methodDefault(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
protected void methodProtected(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
public void methodPublic(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
}
orderTest
package OOP_Zhong;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderDefault = 1;
order.orderProtected = 2;
order.orderPublic = 3;
// order.orderPrivate 同一个包下的不同类,不可以互相调用私有属性
order.methodDefault();
order.methodProtected();
order.methodPublic();
}
}
同一个包的子类
package OOP_NEW;
import OOP_zhong.Order;
public class SubOrder extends Order{
public void method(){
orderProtected = 1;
orderPublic = 2;
methodProtected();
methodPublic();
//在不同包的子类中,不能调用Order类中声明为private和缺省的权限的属性、方法
// orderDefault = 3;
// orderPrivate = 4;
//
// methodDefault();
// methodPrivate();
}
}
04 super 关键词
Person类
public class Person {
String name;
int age;
int id = 1003; //身份证号
public Person(){
System.out.println("我无处不在");
}
public Person(String name){
this.name = name;
}
public Person(String name,int age){
this(name);
this.age = age;
}
public void eat(){
System.out.println("人,吃饭");
}
public void walk(){
System.out.println("人,走路");
}
}
Student类
public class Student extends Person{
String major;
int id = 1002; //学号
public Student(){
}
// 构造器
public Student(String name,int age,String major){
// this.age = age;
// this.name = name;
super(name,age); // 调用父类的构造器
this.major = major;
}
public Student(String major){
this.major = major;
}
//子类中方法重写了
public void eat(){
System.out.println("学生多吃有营养的食物");
}
public void Study(){
System.out.println("学生,学习知识。");
this.eat();
//如果,想调用父类中被重写的,不想调用子类中的方法,可以:
super.eat();
super.walk();//子父类中未重写的方法,用"this."或"super."调用都可以
}
public void show(){
System.out.println("name = " + this.name + ",age = " + super.age);
System.out.println("id = " + this.id);
System.out.println("id = " + super.id);
}
}
调用父类的构造器
子类中所有的 构造 器 默认 都会访问父类中 空参数 的 构造 器
当父类中没有空参数的构造器时 子类的构造器必须通过 this( 参数列表 或者 super( 参数列表 语句指定调用本类或者父类中相应的构造器 。 同时 只能 二选一 且 必须 放在构造 器 的 首 行
如果子类构造器中既未显式调用父类或本类的构造器且父类中又没有无参的构造器 则编译出错
4.2 练习
Account类(父类)
/*
* 写一个名为Account的类模拟账户。该类的属性和方法如下图所示。
* 该类包括的属性:账号id,余额balance,年利率annualInterestRate;
* 包含的方法:访问器方法(getter和setter方法),
* 返回月利率的方法getMonthlyInterest(),
* 取款方法withdraw(),存款方法deposit()。
*
*/
public class Account {
private int id;
protected double balance; // 这里要改成Protected 供子类修改调用
private double annualInterestRate; //年利率
public Account(int id, double balance, double annualInterestRate) {
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnualInterestRate() {
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
public double getMonthlyInterest(){
return annualInterestRate / 12;
}
public void withdraw (double amount) {
if(amount > this.balance){
System.out.println("余额不足");
}else{
this.balance -= amount;
}
}
public void deposit (double amount){
this.balance += amount;
}
}
CheckAccount类
public class CheckAccount extends Account{
private double overdraft;
// 子类的构造器
public CheckAccount(int id, double balance,double annualInterestRate, double overdraft){
super(id,balance,annualInterestRate);
this.overdraft = overdraft;
}
public double getOverdraft() {
return overdraft;
}
public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
}
@Override
public void withdraw(double amount) {
if(amount <= this.balance){
super.balance -= amount; // 这里要修改父类的balance值,所以要将父类中值类型改为Protected
}else{
double overdraft_nedded = amount - this.balance;
if (overdraft_nedded < this.overdraft){
this.balance = 0;
this.overdraft -= overdraft_nedded;
}else{
System.out.println("超过透支金额");
}
}
}
// 主程序 测试类
public static void main(String[] args){
CheckAccount account = new CheckAccount(1122, 20000,
0.045, 5000);
account.withdraw(5000);
System.out.println("您的账户余额为" + account.balance);
System.out.println("您的可透支余额为" + account.overdraft);
account.withdraw(18000);
System.out.println("您的账户余额为" + account.balance);
System.out.println("您的可透支余额为" + account.overdraft);
account.withdraw(3000);
System.out.println("您的账户余额为" + account.balance);
System.out.println("您的可透支余额为" + account.overdraft);
}
}
05 子类对象实例化过程
/*
* 子类对象实例化的全过程
*
* 1.从结果上看:
* 子类继承父类以后,就获取了父类中声明的属性或方法。
* 创建子类的对象中,在堆空间中,就会加载所有父类中声明的属性。
*
* 2.从过程上看:
* 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类构造器,
* 直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类结构,所以才可以看到内存中有父类中的结构,子类对象可以考虑进行调用。
*
* 明确:虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。
*/
public class InstanceTest {
}
06 面向对象特征之三:多态性
多态性指方法的多态性
- 多态性,是面向对象中最重要的概念 在 Java 中 的 体现:
- 对象的 多态性:父类的引用指向子类的对象
- 可以 直接应用在抽象类和 接口上
Person类
public class Person {
String name;
int age;
public void eat(){
System.out.println("人,吃饭");
}
public void walk(){
System.out.println("人,走路");
}
}
Woman类
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("女人,窈窕的走路。");
}
}
Man类
public class Man extends Person{
boolean isSmoking;
public void earnMoney(){
System.out.println("男人负责工作养家");
}
public void eat() {
System.out.println("男人多吃肉,长肌肉");
}
public void walk() {
System.out.println("男人霸气的走路");
}
}
测试
public class Per {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
MAN man = new MAN();
man.eat();
man.age = 25;
man.earnMoney();
//************************************
//对象的多态性,父类的引用指向子类的对象
Person p2 = new MAN();
//多态的使用:当调用子父类同名同参数方法时,实际调用的是子类重写父类的方法---虚拟方法调用
p2.eat(); //男人多吃肉,长肌肉
p2.walk(); //男人霸气的走路
// p2.earnMoney(); //但是不能调用子类中独有的方法,报错
}
}
举例
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 animal = new Dog();
animal.eat();
animal.shout();
}
//如果没有多态性,就会写很多如下的方法,去调用
//public void func(Dog dog){
// dog.eat();
// dog.shout();
//}
// public void func(Cat cat){
// cat.eat();
//}
}
class Animal{
public void eat(){
System.out.println("动物,进食");
}
public void shout(){
System.out.println("动物:叫");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void shout() {
System.out.println("汪!汪!汪!");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void shout() {
System.out.println("喵!喵!喵!");
}
}
6.1 虚拟方法调用(补充)
正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
虚拟方法调用(多态情况下)
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父
类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法
确定的。
Person e = new Student();
e.getInfo //调用 Student 类的 getInfo 方法
编译时 e 为 Person 类型,而方法的调用是在运行时确定的,所以调用的是 Student 类
的 getInfo 方法。
import java.util.Random;
/*
* 2.从编译和运行的角度看:
* 重载,是指允许存在多个同名方法,而这些方法的参数不同。
* 编译器根据方法不同的参数表,对同名方法的名称做修饰。
* 对于编译器而言,这些同名方法就成了不同的方法。
* 它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,
* 即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,
* 编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
* 而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,
* 这称为“晚绑定”或“动态绑定”。
*/
//面试题:多态是编译时行为还是运行时行为? // 运行时行为
//证明如下:
class Animal {
protected void eat() {
System.out.println("animal eat food");
}
}
class Cat extends Animal {
protected void eat() {
System.out.println("cat eat fish");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("Dog eat bone");
}
}
class Sheep extends Animal {
public void eat() {
System.out.println("Sheep eat grass");
}
}
public class InterviewTest {
public static Animal getInstance(int key) {
switch (key) {
case 0:
return new Cat ();
case 1:
return new Dog ();
default:
return new Sheep ();
}
}
public static void main(String[] args) {
int key = new Random().nextInt(3);
System.out.println(key);
Animal animal = getInstance(key);
animal.eat();
}
}
运行时行为指:在方法调用时才会确定调用类型
6.2、向下转型的使用
PersonTest
public class PersonTest {
public static void main(String[] args) {
Person p2 = new Man();
// 如何才能调用子类所特有的属性和方法?
// 使用强制类型转换符,也可称为:向下转型
Man m1 = (Man) p2;
m1.earnMoney();
m1.isSmoking = true;
// 使用强转时,可能出现ClassCastException异常
// Woman w1 = (Woman)p2;
// w1.goShopping();
if (p2 instanceof Woman) {
Woman w1 = (Woman) p2;
w1.goShopping();
System.out.println("**********Woman*********");
}
if (p2 instanceof Man) {
Man m2 = (Man) p2;
m2.earnMoney();
System.out.println("*********Man************");
}
if (p2 instanceof Person) {
System.out.println("***********Person************");
}
if (p2 instanceof Object) {
System.out.println("***********object************");
}
// ("*********Man************");
//***********Person************
//***********object************
6.2.1 instanceof 操作符
类型转换: instanceof 引用类型 编译是否通过:x 和 y之间有没有子父关系,如果有,则编译成功 如果没有: man woman 编译无法通过
/*
* instanceof关键字的使用
*
* a instanceof A:判断对象a是否是类A的实例。如果,返回true,如果不是,返回false;
*
* 使用情境:为了避免在向下转型时出现ClassCastException异常,我们在进行向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
*
* 如果a instanceof A返回true,则a instanceof B也返回true。 其中类B是类A的父类。
*
*/
-
T/F : a instanceof A:判断对象a是否是类A的实例。如果,返回true,如果不是,返回false; object 》 person 》 student - teacher object > String Object object = new Student(); System.out.println(object instancof Student);// true System.out.println(object instancof Person); System.out.println(object instancof object); System.out.println(object instancof teacher);// false System.out.println(object instancof String);//编译通过,返回false
6.2.2 练习
练习一
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 调用子类中的方法,但不能覆盖父类的实例变量
}
}
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);
}
}
练习二
/*
* 建立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”
*
*/
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;
}
}
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");
}
}
}
/*
Name: person
age: 50
school: pku
a student
a person
a student
a person
*/
练习三
package OOP_Zhong;
// 测试程序
public class GeometricTest {
public static void main(String[] args){
GeometricTest test = new GeometricTest();
// 举例测试
Circle c1 = new Circle("black", 2.0, 2.0);
System.out.println(test.displayGeometricObject(c1));
MyRectangle rectangle1 = new MyRectangle("red",3.2,2.1,3.5);
System.out.println(test.displayGeometricObject(rectangle1));
System.out.println(test.equalsArea(c1,rectangle1));
}
public boolean equalsArea(GeometricObject o1,GeometricObject o2){
return o1.findArea() == o2.findArea();
}
public double displayGeometricObject(GeometricObject o1){
return o1.findArea();
}
}
// 输出:12.56
//7.3500000000000005
// false
// 几何形状类
class GeometricObject{
private String color;
private 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;
}
}
// 圆类
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;
}
public double findArea(){
return 3.14 * radius * radius;
}
}
// 矩形类
class MyRectangle extends GeometricObject{
private double width;
private double height;
public MyRectangle(String color, double weight, double width, double height) {
super(color, weight);
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;
}
public double findArea() {
return height * width;
}
}
面试题拓展
public static void main(String[] args) {
Base1 base = new Sub1();
base.add(1, 2, 3); //调用的是子类的方法 sub_1,子类对add()进行了重写
Base1 base1 = new Base1();
base1.add(1, 2, 3); // 调用父类方法,
Sub1 s = (Sub1)base; // 强转为子类
s.add(1,2,3); // sub_2
}
}
class Base1 {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub1 extends Base1 {
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");
}
}
07 Object类的使用
java.lang.Object类
* 1.Object类是所有Java类的根父类;
* 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
* 3.Object类中的功能(属性、方法)就具有通用性。
* 属性:无
* 方法:equals() / toString() / getClass() / hashCode() / clone() /finalize()
* wait() 、notify()、notifyAll()
*
* 4.Object类只声明了一个空参的构造器。
*
* 面试题:
* final、finally、finalize的区别?
public class ObjectTest {
public static void main(String[] args) {
}
}
class Order{
}
7.1Object类中的主要结构
7.2 == 和 equals()
== 比较运算符
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
- 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
- int it = 65 ; float fl =65.0f return(it == fl)----> true
equals()
- .是一个方法,而非运算符
- 只能适用于引用数据类型。
- Object类中equals()的定义:
* public boolean equals(Object obj){
* return (this == obj);
* }
* 说明:Object类中定义的equals()和==的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。
- 像String、Date、File、包装类等都重写了Object类中的equals()方法.
两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同。
- 5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们
就需要对Object类中的equals()进行重写。
重写的原则:比较两个对象的实体内容是否相同。
举例
public class EqualsTest {
public static void main(String[] args) {
//基本数据类型
int i = 10;
int j = 10;
double d = 10.0;
System.out.println(i == j); //true
System.out.println(i == d); //true
// boolean b =true;
// System.out.println(i == b); // 不能编译
char c = 10;
System.out.println(i == c); //true
char c1 = 'A';
char c2 = 65;
System.out.println(c1 == c2); //true
//引用数据类型
Customer cust1 = new Customer("Tom" ,21);
Customer cust2 = new Customer("Tom" ,21);
System.out.println(cust1 == cust2); //false 地址值不同
String str1 = new String("BAT");
String str2 = new String("BAT");
System.out.println(str1 == str2); //false
System.out.println("*************************");
System.out.println(cust1.equals(cust2)); //false 需要在类中重写equals方法
System.out.println(str1.equals(str2)); //true
Date date1 = new Date(23432525324L);
Date date2 = new Date(23432525324L);
System.out.println(date1.equals(date2)); //true
}
}
在类中重写equals()
public class Customer {
private String name;
private int 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;
}
public Customer() {
super();
}
public Customer(String name, int age) {
super();
this.name = name;
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)是否相同
//手动实现equals()的重写
// @Override
// public boolean equals(Object obj) {
//
System.out.println("Customer equals()....");
// if(this == obj){
// return true;
// }
//
// if(obj instanceof Customer){
// Customer cust = (Customer)obj;
// //比较两个对象的属性是否都相同
if(this.age == cust.age && this.name.equals(cust.name)){
return true;
}else{
return false;
}
//
// //或
// return this.age == cust.age && this.name.equals(cust.name);
// }
//
// return false;
// }
}
Equals练习
public class OderEqualsTest {
private int orderId;
private String oderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOderName() {
return oderName;
}
public void setOderName(String oderName) {
this.oderName = oderName;
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof OderEqualsTest){
OderEqualsTest oder = (OderEqualsTest) obj; // 这里必须要向下转型
return oder.oderName == this.oderName && oder.orderId == this.orderId;
}
return false;
}
}
7.3、toString的使用
public String toString() {
return "Customer [name=" + name + ", age=" + age + "]";
}
Object类中toString()的使用
- 当我们输出一个引用对象时,实际上就是调用当前对象的toString()
Object类中toString的定义方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
3.像String、Date、File、包装类等都重写了Object类中的toString()方法。
使得在调用toString()时,返回"实体内容"信息.
4.自定义类如果重写toString()方法,当调用此方法时,返回对象的"实体内容".
练习
import org.junit.Test;
/*
* 2.基本数据类型、包装类、String三者之间的相互转换。
*
*/
public class WrapperTest {
//String类型---> 基本数据类型、包装类,调用包装类的parseXxx()
@Test
public void test5(){
String str1 = "123";
// String str1 = "123a";
//错误的情况,可能会报错
// int num1 = (int)str1;
// Integer in1 = (Integer)str1;
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1); //124
String str2 = "true";
Boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1); //true
}
//基本数据类型、包装类---》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"
}
/*
* JDK 5.0 新特性:自动装箱与自动拆箱
*/
@Test
public void test3(){
// int num1 = 10;
// //基本数据类型 --》 包装类的对象
// method(num1); //Object obj = 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);
}
//包装类 --》 基本数据类型:调用包装类的xxxValue()
@Test
public void test2() {
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);
Float f1 = new Float(12.3f);
float f2 = f1.floatValue();
System.out.println(f2 + 1);
}
//基本数据类型--》包装类,调用包装类的构造器
@Test
public void test1() {
int num1 = 10;
// 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 b1 = new Boolean(true);
Boolean b2 = new Boolean("true");
Boolean b3 = new Boolean("true123");
System.out.println(b3); //false
Order order = new Order();
System.out.println(order.isMale); //false
System.out.println(order.isFemale); //null
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
08 包装类的使用
基本数据类型转换为包装类
java提供八种基本数据类型对应的包装类,让基本数据类型 也有类的特性
//基本数据类型--》包装类,调用包装类的构造器
@Test
public void test1() {
int num1 = 10;
// System.out.println(num1.toString()); //10
Integer in1 = new Integer(num1);
System.out.println(in1.toString()); //10
Integer in2 = new Integer("123");
System.out.println(in2.toString()); // 123
//报异常
// 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");
Boolean b3 = new Boolean("true123");
System.out.println(b3); //false
Order order = new Order();
System.out.println(order.isMale); //false
System.out.println(order.isFemale); //null 这里已经是一个类了,引用数据类型
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
包装类转换为基本数据类型
//包装类 --》 基本数据类型:调用包装类的xxxValue()
@Test
public void test2() {
Integer in1 = new Integer(12);
int i1 = in1.intValue(); // i1转换为 int型数据
System.out.println(i1 + 1);
Float f1 = new Float(12.3f);
float f2 = f1.floatValue();
System.out.println(f2 + 1);
}
jdk5.0 自动装箱,自动拆箱新特性
public void test3(){
// int num1 = 10;
// //基本数据类型 --》 包装类的对象
// method(num1); //Object obj = 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)
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()
@Test
public void test5(){
String str1 = "123";
// String str1 = "123a";
//错误的情况,可能会报错
// int num1 = (int)str1;
// Integer in1 = (Integer)str1; //强转必须有字子父类关系
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1); //124
String str2 = "true";
Boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1); //true
}
转换总结
8.1 练习题
练习一
import org.junit.Test;
/*
* 如下两个题目输出结果相同吗?各是什么:
*/
public class InterViewTest {
@Test
public void test(){
Object o1= true? new Integer(1) : new Double(2.0);
System.out.println(o1);// 1.0 三元运算符前后数据类型要一致,这里对int属于据类型进行了一个提升
}
@Test
public void test2(){
Object o2;
if(true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);// 1
}
练习二
public void method1() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //false
//Integer内部定义了一个IntegerCache结构,IntegerCache中定义Integer[]
//保存了从-128-127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在其中时,
//可以直接使用数组中的元素,不用再去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
}
练习二
public void method1() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); //false
/*
Integer内部定义了一个IntegerCache结构,IntegerCache中定义Integer[]
保存了从-128-127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在其中时,
可以直接使用数组中的元素,不用再去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
}
练习三
import java.util.Scanner;
import java.util.Vector;
/*
* 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),
* 找出最高分,并输出学生成绩等级。
*
* 提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。
* 而向量类java.util.Vector可以根据需要动态伸缩。
*
* 创建Vector对象:Vector v=new Vector();
* 给向量添加元素:v.addElement(Object obj); //obj必须是对象
* 取出向量中的元素:Object obj=v.elementAt(0);
* 注意第一个元素的下标是0,返回值是Object类型的。
* 计算向量的长度:v.size();
* 若与最高分相差
* 10分内:A等;
* 20分内:B等;
* 30分内:C等;
* 其它:D等
*
*/
public class VectorTest {
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)方式,给Vector中添加数组
int maxScore = 0;
for (;;) {
System.out.println("请输入学生成绩(以负数代表输入结束)");
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);//多态
// jdk5.0之后:
v.addElement(score);// 自动装箱
// 4.获取学生成绩的最大值
if (maxScore < score) {
maxScore = score;
}
}
// 5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级。
char level;
for (int i = 0; i < v.size(); i++) {
Object obj = v.elementAt(i);
// jdk 5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
// jdk 5.0之后:
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);
}
}
}