第八天:封装、继承、抽象类

第八天:封装、继承、抽象类
今日内容介绍
继承
抽象类
第1章继承
1.1继承的概念
在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。例如:老师和学生都属于人的一种,程序中便可以描述老师和学生都继承自人类,这些老师和学生以会形成一个继承体系

在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有非私有的属性和方法。
1.2继承的格式&使用
在程序中,如果想声明一个类继承另一个类,需要使用extends关键字。
格式:
class 子类 extends 父类 {}
接下来通过一个案例来学习子类是如何继承父类的,如下所示
//类中我们需要定义哪些成员变量(属性)和成员方法(行为)
public class Person {
//人的属性
String name;

//人的行为
public void sleep(){
System.out.println(name+“在睡觉”);
}
}

public class Teacher extends Person{
//老师特有的功能:教书
public void teach(){
System.out.println(name+“教Java”);//这个name是从Person中继承下来的
}
}

public class Demo {
public static void main(String[] args) {
Teacher t=new Teacher();
t.name=“老王”;//调用父类的属性
t.sleep();//调用父类的方法
t.teach();//调用自身类中的方法
}
}

1.3继承的好处&注意事项
继承的好处:
1、继承的出现提高了代码的复用性,提高软件开发效率。
2、继承的出现让类与类之间产生了关系,提供了多态的前提。
1.提高了代码的复用性
在父类中已经定义的成员变量和成员方法,在子类不用在重复定义,因为子类会把父类的非私有成员变量和成员方法继承下来,直接使用
2.继承的出现让类与类之间产生了父子关系

在类的继承中,需要注意一些问题,具体如下:
1、在Java中,类只支持单继承,不允许多继承,也就是说一个类只能有一个直接父类,例如下面这种情况是不合法的。
class A{}
class B{}
class C extends A,B{} // C类不可以同时继承A类和B类
2、多个类可以继承一个父类,例如下面这种情况是允许的。
class A{}
class B extends A{}
class C extends A{} // 类B和类C都可以继承类A
3、在Java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类,例如C类继承自B类,而B类又可以去继承A类,这时,C类也可称作A类的子类。下面这种情况是允许的。
class A{}
class B extends A{} // 类B继承类A,类B是类A的子类
class C extends B{} // 类C继承类B,类C是类B的子类,同时也是类A的子类
4、在Java中,子类和父类是一种相对概念,也就是说一个类是某个类父类的同时,也可以是另一个类的子类。例如上面的这种情况中,B类是A类的子类,同时又是C类的父类。
1.4继承-子父类中成员变量的特点
了解了继承给我们带来的好处,提高了代码的复用性。继承让类与类或者说对象与对象之间产生了关系。那么,当继承出现后,类的成员之间产生了那些变化呢?
类的成员重点学习成员变量、成员方法的变化。
成员变量:如果子类父类中出现不同名的成员变量,这时的访问是没有任何问题。
看如下代码:
class Fu{
//Fu中的成员变量。
int num = 5;
}
class Zi extends Fu{
//Zi中的成员变量
int num2 = 6;
//Zi中的成员方法
public void show()
{
//访问父类中的num
System.out.println(“Fu num=”+num);
//访问子类中的num2
System.out.println(“Zi num2=”+num2);
}
}
class Demo
{
public static void main(String[] args)
{
Zi z = new Zi(); //创建子类对象
z.show(); //调用子类中的show方法
}
}
代码说明:Fu类中的成员变量是非私有的,子类中可以直接访问,若Fu类中的成员变量私有了,子类是不能直接访问的。

当子父类中出现了同名成员变量时,在子类中若要访问父类中的成员变量,必须使用关键字super来完成。Super关键字可以用来访问父类的非私有的成员。super今天不做具体讲解,在后面的课程会详细讲解
在子类中,访问父类中的成员变量格式:
super.父类中的成员变量
看如下代码:
class Fu
{
//Fu中的成员变量。
int num = 5;
}
class Zi extends Fu
{
//Zi中的成员变量
int num = 6;
void show()
{
//子父类中出现了同名的成员变量时
//在子类中需要访问父类中非私有成员变量时,需要使用super关键字
//访问父类中的num
System.out.println(“Fu num=”+super.num);
//访问子类中的num2
System.out.println(“Zi num2=”+this.num);
}
}
class Demo5
{
public static void main(String[] args)
{
Zi z = new Zi(); //创建子类对象
z.show(); //调用子类中的show方法
}
}
1.5继承-子父类中成员方法特点-重写&应用
子父类中成员方法的特点
当在程序中通过对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
看如下代码:
class Fu{
public void show(){
System.out.println(“Fu类中的show方法执行”);
}
}
class Zi extends Fu{
public void show2(){
System.out.println(“Zi类中的show2方法执行”);
}
}
public class Test{
public static void main(String[] args) {
Zi z = new Zi();
z.show(); //子类中没有show方法,但是可以找到父类方法去执行
z.show2();
}
}

成员方法特殊情况——覆盖
子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为override重写、复写或者覆盖。
class Fu
{
public void show()
{
System.out.println(“Fu show”);
}
}
class Zi extends Fu
{
//子类复写了父类的show方法
public void show()
{
System.out.println(“Zi show”);
}
}

方法重写(覆盖)的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
举例:比如手机,当描述一个手机时,它具有发短信,打电话,来电显示功能,后期由于手机需要在来电显示功能中增加显示姓名和头像,这时可以重新定义一个类描述智能手机,并继承原有描述手机的类。并在新定义的类中覆盖来电显示功能,在其中增加显示姓名和头像功能。
在子类中,访问父类中的成员方法格式:
super.父类中的成员方法();
看如下代码:
public class Test {
public static void main(String[] args) {
new NewPhone().showNum();
}
}

//手机类
class Phone{
public void sendMessage(){
System.out.println(“发短信”);
}
public void call(){
System.out.println(“打电话”);
}
public void show(){
System.out.println(“来电显示号码”);
}
}

//智能手机类
class NewPhone extends Phone{

//覆盖父类的来电显示号码功能,并增加自己的显示姓名和图片功能
public void show(){
	//调用父类已经存在的功能使用super
	super.show();
	//增加自己特有显示姓名和图片功能
	System.out.println("显示来电姓名");
	System.out.println("显示头像");
}

}
1.6方法重写的必备条件
重写需要注意的细节问题:
子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
class Fu(){
void show(){}
public void method(){}
}
class Zi() extends Fu{
public void show(){} //编译运行没问题
void method(){} //编译错误
}
写法上稍微注意:必须一模一样:方法的返回值类型 方法名 参数列表都要一样。
总结:当一个类是另一个类中的一种时,可以通过继承,来继承属性与功能。如果父类具备的功能内容需要子类特殊定义时,进行方法重写。
1.7重写和重载的区别

/*
*1.重载(overload)和重写(override)的区别

  • 修饰符 返回值类型 方法名(形参列表){
  • }
  • public int getSum(int a,int b){
  • }
  • public double getSum(double a,double b){
  • }
  • 重载不一定有继承关系,重写一定有继承关系
  • a.修饰符:
  • 重载对两个方法没有任何要求
    
  • 重写对权限修饰符有要求,子类的方法的权限>=父类的方法的权限
    
  • b.返回值类型:
  • 重写要求子类的方法和父类中被重写的方法一致
    
  • 重载对两个方法返回值类型没有要求
    
  • c.方法名:
  • 重写要求子类的方法和父类中被重写的方法方法名一致
    
  • 重载要求两个方法方法名必须一致
    
  • d.形参列表:
  • 重写要求子类的方法和父类中被重写的方法的形参列表一致
    
  • 重载要求两个方法的形参列表必须不同(形参类型不同,形参个数不同,形参类型顺序不同)
    

*/
//重载在继承中应用
//从父类中继承的方法和子类中的方法构成重载关系
class Father{
public int getSum(int a,int b){
return a+b;
}
}

class Son extends Father{
public double getSum(double a,double b){
return a+b;
}
public double getSum(double a,double b,double c){
return a+b+c;
}
}
第2章super关键字与super语句
2.1子父类中构造方法的调用
在创建子类对象时,父类的构造方法会先执行,因为子类中所有构造方法的第一行有默认的隐式super();语句。
格式:
调用本类中的构造方法
this(实参列表);
调用父类中的空参数构造方法
super();
调用父类中的有参数构造方法
super(实参列表);

为什么子类对象创建都要访问父类中的构造方法?因为子类继承了父类的内容,所以创建对象时,必须要先看父类是如何对其内容进行初始化的,看如下程序:

public class Fu {
public Fu(int i){
System.out.println(i);
}
public Fu(){
System.out.println(“Fu的构造方法”);
}
}

/*在每个类的构造方法的第一行默认有一个语句:

  • super();
  • 作用:
  • 调用父类的构造方法

*注意:

  • 可以通过super(参数)来调用父类中指定的构造方法
  • 如果在第一行写了super(参数)语句,就没有默认的
  • super();语句
    */
    public class Zi extends Fu{
    public Zi(){
    //super();//即使不写默认也有
    super(3);
    System.out.println(“Zi的构造方法”);
    }
    }

public class Demo02 {
public static void main(String[] args) {
Zi zi=new Zi();
}
}

通过结果发现,子类构造方法执行时中,调用了父类构造方法,这说明,子类构造方法中有一句super()。
那么,子类中的构造方法为什么会有一句隐式的super()呢?
原因:子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去执行父类的初始化动作。这样,才可以使用父类中的内容。
当父类中没有空参数构造方法时,子类的构造方法必须有显示的super语句,指定要访问的父类有参数构造方法。
2.2super语句案例
练习:描述学生和工人这两个类,将他们的共性name和age抽取出来存放在父类中,并提供相应的get和set方法,同时需要在创建学生和工人对象就必须明确姓名和年龄

public class Person {
private String name;
private int age;

public Person(){
	
}
/*Person的构造方法*/
public Person(String name,int age){//name="张工",age=23
	this.name=name;//this.name="张工"
	this.age=age;//this.age=23
}


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 class Worker extends Person{

/* public Worker(){
super();
}/
/

//由于工人也具有姓名,年龄,我们可以在工人中再定义姓名年龄
//但是父类Person中已经定义了name,age,我们在子类中再定义
//name,age,显得重复,代码复用性很低
private String name;
private int age;

public Worker(String name,int age){
	this.name=name;
	this.age=age;
}*/

public Worker(String name,int age){//name="张工" age=23
	super(name,age);//super("张工",23);
}

public void work(){
	System.out.println(getName()+"工人在努力工作");
}

}

2.3super()语句注意事项
1.如果子类的构造方法第一行写了this语句调用了本类其他构造方法,那么super调用父类的语句还有吗?
这时是没有的,因为this()或者super(),只能定义在构造方法的第一行,因为初始化动作要先执行。
2.父类构造方法中是否有隐式的super语句呢?
也是有的。记住:只要是构造方法默认第一行都是super();
父类的父类是谁呢?super调用的到底是谁的构造方法呢?
Java体系在设计,定义了一个所有对象的父类Object

注意:
类中的构造方法默认第一行都有隐式的super()语句,在访问父类中的空参数构造方法。所以父类的构造方法既可以给自己的对象初始化,也可以给自己的子类对象初始化。
如果默认的隐式super()语句在父类中没有对应的构造方法,那么必须在构造方法中通过this或者super的形式明确要调用的构造方法。
第3章抽象类
3.1抽象类-产生
当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的功能具体实现方式,那么这些方法都有具体的方法体。
但是有的时候,某个父类只是知道子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。比如一个图形类应该有一个求周长的方法,但是不同的图形求周长的算法不一样。那该怎么办呢?
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是方法功能声明相同,但方法功能主体不同。那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
当定义了抽象函数的类也必须被abstract关键字修饰,被abstract关键字修饰的类是抽象类。
3.2抽象类&抽象方法的定义
抽象方法定义的格式:
public abstract 返回值类型 方法名(参数);
抽象类定义的格式:
abstract class 类名 {
}
看如下代码:
/* 当我们画一个形状的时候,我们可以求出这个形状的周长和面积

  • 长方形
  • 周长:2*(长+宽)
  • 面积:长*宽
  • 正方形
  • 周长:4*边长
  • 面积:边长*边长
  • 抽象方法的由来:
  • 由于在我们形状类中,这个形状是不确定的,因此求周长的方法体和求面积的方法体都无法写
    
  • 因此我们就不写这两个方法的方法体,但是需要在返回值类型前面加上abstract
    
  • 抽象类的由来:
  • 含有抽象方法的类一定是抽象类(在class的前面加abstract修饰)
    

*/

//定义了一个形状类
public abstract class Shape {
//求周长的方法
/*
*形状类中定义的求周长的方法
* 在周长的方法中,你既不能定义长方形的求周长的公式
* 也不能定义正方形的求周长的公式
/
public abstract int getZhouChang();
/

*形状类中定义的求面积的方法
* 在面积的方法中,你既不能定义长方形的求面积的公式
* 也不能定义正方形的求面积的公式
*/
public abstract int getArea();
}

//长方形是形状一种
//在长方形类中需要重写所有的抽象方法,才能保证长方形类不是抽象类
public class ChangFangXing extends Shape{
int length;//长方形的长
int width;//长方形的宽

@Override
public int getZhouChang() {
	return 2*(width+length);
}

@Override
public int getArea() {
	return width*length;
}

}

public class ZhengFangXing extends Shape{
int b;//边长
@Override
public int getZhouChang() {
// TODO Auto-generated method stub
return 4*b;
}

@Override
public int getArea() {
	// TODO Auto-generated method stub
	return b*b;
}

}

public class Demo {
public static void main(String[] args) {
// Shape s=new Shape();//由于Shape是一个抽象类,不能创建对象

   ChangFangXing cfx=new ChangFangXing();
   cfx.length=3;
   cfx.width=7;
   System.out.println(cfx.getZhouChang());
   System.out.println(cfx.getArea());
   
   
   ZhengFangXing zfx=new ZhengFangXing();
   zfx.b=5;
   System.out.println(zfx.getZhouChang());
   System.out.println(zfx.getArea());
}

}

3.3抽象类的特点:
1、抽象类和抽象方法都需要被abstract修饰。抽象方法一定要定义在抽象类中。
2、抽象类不可以直接创建对象,原因:调用抽象方法没有意义。
3、只有重写了抽象类中所有的抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类。
之所以继承抽象类,更多的是在思想,是面对共性类型操作会更简单。

3.4抽象类的细节问题:
1、抽象类一定是个父类?
是的,因为不断抽取而来的。
2、抽象类中是否可以不定义抽象方法。
是可以的,那这个抽象类的存在到底有什么意义呢?不让该类创建对象,方法可以直接让子类去使用
3、抽象关键字abstract不可以和哪些关键字共存?
1、private:私有的方法子类是无法继承到的,也不存在覆盖,而abstract和private一起使用修饰方法,abstract既要子类去实现这个方法,而private修饰子类根本无法得到父类这个方法。互相矛盾。
2、final,暂时不关注,后面学
3、static,暂时不关注,后面学

第4章综合案例—员工类系列定义
4.1案例介绍
某IT公司有多名员工,按照员工负责的工作不同,进行了部门的划分(研发部员工、维护部员工)。研发部根据所需研发的内容不同,又分为JavaEE工程师、Android工程师;维护部根据所需维护的内容不同,又分为网络维护工程师、硬件维护工程师。
公司的每名员工都有他们自己的员工编号、姓名,并要做它们所负责的工作。
工作内容
JavaEE工程师:员工号为xxx的 xxx员工,正在研发淘宝网站
Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机
请根据描述,完成员工体系中所有类的定义,并指定类之间的继承关系。进行XX工程师类的对象创建,完成工作方法的调用。

员工类:
属性:工号
方法:抽象方法 work()

研发部员工:
属性:类型
方法:抽象方法 work()

必须提供带参构造方法:
4.2案例分析
根据上述部门的描述,得出如下的员工体系图

根据员工信息的描述,确定每个员工都有员工编号、姓名、要进行工作。则,把这些共同的属性与功能抽取到父类中(员工类),关于工作的内容由具体的工程师来进行指定。
分析:
父类—员工类
属性:工号
方法:抽象的方法 工作

工作内容
JavaEE工程师:员工号为xxx的 xxx员工,正在研发淘宝网站
Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机
创建JavaEE工程师对象,完成工作方法的调用
4.3案例代码实现
根据员工体系图,完成类的定义
定义员工类(抽象类)
public abstract class Employee {
private String id;// 员工编号
private String name; // 员工姓名

public String getId() {
	return id;
}
public void setId(String id) {
	this.id = id;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}

//工作方法(抽象方法)
public abstract void work(); 

}

定义研发部员工类Developer 继承 员工类Employee
public abstract class Developer extends Employee {
}

定义维护部员工类Maintainer 继承 员工类Employee
public abstract class Maintainer extends Employee {
}

定义JavaEE工程师 继承 研发部员工类,重写工作方法
public class JavaEE extends Developer {
@Override
public void work() {
System.out.println(“员工号为 " + getId() + " 的 " + getName() + " 员工,正在研发淘宝网站”);
}
}

定义Android工程师 继承 研发部员工类,重写工作方法
public class Android extends Developer {
@Override
public void work() {
System.out.println(“员工号为 " + getId() + " 的 " + getName() + " 员工,正在研发淘宝手机客户端软件”);
}
}

定义Network网络维护工程师 继承 维护部员工类,重写工作方法
public class Network extends Maintainer {
@Override
public void work() {
System.out.println(“员工号为 " + getId() + " 的 " + getName() + " 员工,正在检查网络是否畅通”);
}
}

定义Hardware硬件维护工程师 继承 维护部员工类,重写工作方法
public class Hardware extends Maintainer {
@Override
public void work() {
System.out.println(“员工号为 " + getId() + " 的 " + getName() + " 员工,正在修复打印机”);
}
}

在测试类中,创建JavaEE工程师对象,完成工作方法的调用
public class Test {
public static void main(String[] args) {
//创建JavaEE工程师员工对象
JavaEE ee = new JavaEE();
//设置该员工的编号
ee.setId(“000015”);
//设置该员工的姓名
ee.setName(“小明”);
//调用该员工的工作方法
ee.work();
}
}
第5章Java的API及Object类
在以前的学习过程中,我们都在学习对象基本特征、对象的使用以及对象的关系。接下来我们开始使用对象做事情,那么在使用对象做事情之前,我们要学习一些API中提供的常用对象。首先在学习API中的Object类之前,先来学习如何使用API。
5.1Java 的API
Java 的API(API: Application(应用) Programming(程序) Interface(接口))
Java API就是JDK中提供给我们使用的类,这些类将底层的代码实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可:
例如Scanner
Scanner scan=new Scanner(System.in);
Int i=scan.nextInt();
在JDK安装目录下有个src.zip文件,这个文件解压缩后里面的内容是所有Java类的源文件。可以在其中查看相对应的类的源码。
我们在每次查看类中的方法时,都打开源代码进行查看,这种方式过于麻烦。其实,我们可以通过查帮助文档的方式,来了解Java提供的API如何使用。如下图操作:查找Object类

通过帮助文档中类与方法的介绍,我们就能够使用这个类了。
5.2Object类概述
Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。所有类在创建对象的时候,最终找的父类就是Object。
在Object类众多方法中,我们先学习equals方法与toString方法,其他方法后面课程中会陆续学到。
5.3equals方法

5.3.1Object原始equals()方法分析:
equals方法,用于比较两个对象是否相同,它其实就是使用两个对象的内存地址在比较。Object类中的equals方法内部使用的就是==比较运算符。
package com.whhp.object01;

public class Person/extends Object/ {

}

package com.whhp.object01;

/*
*Object类:

  • 所有类都直接或间接继承Object类,所有类都继承了Object类中非私有的方法

  • boolean equals(Object obj):比较两个对象,结果要么true,要么是false

  • String toString()

  • ctrl+shift+T 输入类名快速打开一个类

  • ctrl+o 在这个类中找成员,输入成员变量或成员方法的名字可以快速定位

  • Object类中的equals方法比较的是两个对象的地址值
    */
    public class Demo01 {
    public static void main(String[] args) {
    //使用Object类中的equals方法
    Person p1=new Person();//p1=1344 (new Person()地址值)
    Person p2=new Person();//p2=2355 (new Person()地址值)

    System.out.println(p1);//打印p1的地址值com.whhp.object01.Person@2e807f85
    System.out.println(p2);//打印p2的地址值com.whhp.object01.Person@76340c9c

    boolean b=p1.equals(p2);//用的是从Object类中继承下来的equals方法
    System.out.println(b);

    boolean b2=p1.equals(p1);
    System.out.println(b2);
    }
    }
    /*
    *Object类中equals源码分析:

  • public boolean equals(Object obj) {
    return (this == obj);
    //this=p1=1344
    //obj=p2=2355
    //相当于 p1==p2

    }

  • ==:

  • 如果比较引用类型比较的是两个引用类型变量存放地址值

  • 如果比较基本类型,比较的是数值

  • int i=3;

  • int j=6

  • System.out.println(i==j);//false

*/

5.3.2重写equals()方法
在开发中要比较两个对象是否相同,经常会根据对象中的属性值进行比较,也就是在开发经常需要子类重写equals方法根据对象的属性值进行比较。如下代码演示:
注意:在复写Object中的equals方法时,一定要注意public boolean equals(Object obj)的参数是Object类型,在调用对象的属性时,一定要进行类型转换,在转换之前必须进行类型判断。
5.3.2.1一个属性的重写
package com.whhp.object02;

/*
*

  • 我们创建两个Person对象代表两个人,我们利用equals(Object obj)方法
  • 比较两个Person对象,其实比较的是两个人对象的地址值
  • 但是从现实生活去考虑,我们判断两个人是否是同一个人,我们通常通过姓名,年龄
  • 身高等 来判断两个人是否是同一个人
  • 假设按照年龄属性来判断:
  • 如果两个人的年龄相同,我们就可以认为两个人是同一个人
  • 如果两个人的年龄不同,我们认为两个人不是同一个人

*/

public class Person/* extends Object */{

private int age;

public Person(int age) {
	this.age = age;
}

// 由于Object类中的equals方法不能贴近我们的现实需求
// 因此我们重写
@Override
public boolean equals(Object obj) {//Object obj=new Obejct();
	/*如果两个人的年龄相同,我们就可以认为两个人是同一个人,返回true
	 * 如果两个人的年龄不同,我们认为两个人不是同一个人,返回false
	 */
	if(this==obj){//代表调用equals方法的对象和传入的对象是同一个对象
		         //就没有必要在比较两者年龄,因为就是同一个人,属性肯定相同
		return true;
	}
	
	
	
	if(!(obj instanceof Person)){//obj指向的类型能否转换为Person类型
		return false;
	}
	
	//为了使用Person中特有属性 age,因此我们要将obj向下转型
	Person p=(Person)obj; //Person p=(Person)new Object();//无法转换
	/*if(this.age==p.age){
		return true;
	}else{
		return false;
	}*/
	
	return this.age==p.age;
}




public int getAge() {
	return age;
}

public void setAge(int age) {
	this.age = age;
}

}

package com.whhp.object02;

public class Demo02 {
public static void main(String[] args) {
//method01();
//method02();
Person p1=new Person(10);
boolean b=p1.equals(p1);
System.out.println(b);
}

private static void method02() {
	Person p1=new Person(10);
	  Object obj=new Object();
	  boolean b= p1.equals(obj);
	  System.out.println(b);
}

private static void method01() {
	   Person p1=new Person(10);
	   Person p2=new Person(20);
	   
	   boolean b=p1.equals(p2);
	   
	   System.out.println(b);
}

}

5.3.2.2多个属性的重写

package com.whhp.object03;

/* Person类中有两个属性

  • 姓名,年龄
  • 比较两个人的姓名和年龄来判断是否是同一个人
  • 如果两个人的姓名和年龄均相同,认为是同一个人
  • 如果两个人的姓名和年龄不同,我们认为两个人不是同一个人
  • alt+shift+s 选择生成构造方法使用字段
  • alt+shift+s 选择生成getter/setter方法
  • 结论:
  • 重写equals的目标:
  •  如果所有的属性值均相同我们返回true
    
  •  至少有一个属性值不同返回false
    

*/
public class Person {
private String name;
private int age;

public Person(String name, int age) {
	super();
	this.name = name;
	this.age = age;
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (this.getClass() != obj.getClass())//if (!(obj instanceof Person)) 
		return false;
	
	Person other = (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;
}

/*	@Override
public boolean equals(Object obj) {
	// 如果两个人的姓名和年龄均相同,认为是同一个人
	// 如果两个人的姓名和年龄不同,我们认为两个人不是同一个人
	if (this == obj) {// 代表调用equals方法的对象和传入的对象是同一个对象
		// 就没有必要在比较两者年龄,因为就是同一个人,属性肯定相同
		return true;
	}

	if (!(obj instanceof Person)) {// obj指向的类型能否转换为Person类型
		return false;
	}
	
	
	// 为了使用Person类中特有属性,我们要把obj向下转型
	Person p = (Person) obj;

	// 通过this和p调用姓名以及年龄去比较
	boolean b1 = this.age == p.age;
	boolean b2 = this.name.equals(p.name);// 利用字符串的equals方法比较两个字符串内容
	if (b1 && b2) {// 如果b1和b2都为真,说明两个人的姓名和年龄均相同
		return true;
	} else {// !b1 || !b2
			// 两个人姓名和年龄至少有一个不同
		return false;
	}
}

/
/
生成getter/setter方法 */
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;
}

}

package com.whhp.object03;

public class Demo03 {
public static void main(String[] args) {
Person p1=new Person(“张三”,10);
Person p2=new Person(“李四”,10);
boolean b=p1.equals(p2);
System.out.println(b);
}
}

5.4toString方法

toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值。
由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。
class Person extends Object{
int age ;
//根据Person类的属性重写toString方法
public String toString() {
return “Person [age=” + age + “]”;
}
}
5.4.1Object原始toString()方法分析
public class Person{
}

/*
*当打印对象的时候默认会调用toString();
*
*
*/
public class Demo04 {
public static void main(String[] args) {
method01();

}

private static void method01() {
	Person p = new Person();
	System.out.println(p.toString());// com.whhp.object04.Person@177c760b
	System.out.println(p);// com.whhp.object04.Person@177c760b
}

}

/*

  • toString()源码分析: public String toString() { return this.getClass().getName() +
  • “@” + Integer.toHexString(hashCode()); }
  • this.getClass().getName()//获取this引用指向的对象所属的 类的名字(包名.类名)
  • //com.whhp.object04.Person
  • Integer.toHexString(hashCode())//获取对象的内存地址值的十六进制形式
    */

5.4.2重写toString()方法

package com.whhp.object04;

/*

  • 我们通过对象调用toString()方法打印对象的地址值没有意义
  • toString重写目标:
  • 返回该类中所有成员变量字符串的拼接形式

*/
public class Person {
private String name;
private int age;

public Person(){
	
}
public Person(String name, int age) {
	super();
	this.name = name;
	this.age = age;
}

//重写掉Object中原始的toString()方法
/*@Override
public String toString() {
   return "name="+name+",age="+age;
}*/

@Override
public String toString() {
	return "Person [name=" + name + ", 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;
}

}

package com.whhp.object04;

/*
*当打印对象的时候默认会调用toString();
*
*
*/
public class Demo04 {
public static void main(String[] args) {
//method01();
Person p=new Person(“张三”,10);
System.out.println(p.toString());
System.out.println§;
}

private static void method01() {
	Person p = new Person();
	System.out.println(p.toString());// com.whhp.object04.Person@177c760b
	System.out.println(p);// com.whhp.object04.Person@177c760b
}

}
/*

  • toString()源码分析: public String toString() { return this.getClass().getName() +

  • “@” + Integer.toHexString(hashCode()); }

  • this.getClass().getName()//获取this引用指向的对象所属的 类的名字(包名.类名)

  • //com.whhp.object04.Person

  • Integer.toHexString(hashCode())//获取对象的内存地址值的十六进制形式
    */
    第6章 final关键字
    6.1final的概念
    继承的出现提高了代码的复用性,并方便开发。但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写。可是当子类继承了这些特殊类之后,就可以对其中的方法进行重写,那怎么解决呢?
    要解决上述的这些问题,需要使用到一个关键字final,final的意思为最终,不可变。final是个修饰符,它可以用来修饰类,类的成员,以及局部变量。
    6.2final的特点
    final修饰类不可以被继承,但是可以继承其他类。

    public final class Fu {

}

/*public class Zi extends Fu {

}
*/
final修饰的方法不可以被重写
public class Fu{
public finl void method(){

}
}

public class Zi extends Fu{
/*
public void method(){

}
*/
}

final修饰的变量称为常量,这些变量只能赋值一次。
public final class Fu {
final int number=4;
final int age;
public Fu(){
//number=5;//加final修饰的成员变量只能赋值一次
age=13;
//age=8;
}

public static void main(String[] args) {
    //1.final修饰局部变量第一种格式
	final int i=3;
    //i=10;
    System.out.println(i);
    
    //2.final修饰局部变量的第二种格式
    final int j;
    j=6;
    //j=5;
    
}

}
引用类型的变量值为对象地址值,地址值不能更改,但是地址内的对象属性值可以修改。

//3.final修饰引用变量
final Fu fu=new Fu();//Fu fu=1311
//fu的值恒定不变
//fu只能赋值一次
//fu=new Fu();//fu=1255,此时无法给fu赋值

    final Fu fu2;
    fu2=new Fu();
   // fu2=new Fu();

修饰成员变量,需要在创建对象前赋值,否则报错。(当没有显式赋值时,多个构造方法的均需要为其赋值。)
public final class Fu {
final int number=4;
final int age;
public Fu(){
//number=5;//加final修饰的成员变量只能赋值一次
age=13;
//age=8;
}
}

需要免费的java基础视频和java企业级开发视频以及项目实战(包含SSM框架详细讲解、activiti流程引擎、springboot、springcloud视频讲解和项目实战课程)可以添加qq:1743337375

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值