面向对象编程三大特征:封装、继承、多态

news2024/12/23 18:07:51

封装、继承、多态

1. 封装

1.1 介绍

        封装(encapsulation)就是把抽象出的数据  [属性] 和对数据的操作  [方法]  封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作 [方法] ,才能对数据进行操作。

1.2 封装的理解和好处

1) 隐藏实现细节:方法(连接数据库)<--调用(传入参数..)
2) 可以对数据进行验证,保证安全合理
                Person {name, age}
                Person p = new Person();
                p.name = "jack" ;
                p.age = 1200;

1.3 封装的实现步骤 (三步)

1) 将属性进行私有化private【不能直接修改属性】
2) 提供一个公共的(public) set 方法,用于对属性判断并赋值
        public void setXxx (类型参数名)0/Xx表示某个属性
                //加入数据验证的业务逻辑
                属性 = 参数名;
        }
3) 提供一个公共的(public)get方法,用于获取属性的值
        public 数据类型 getXxx() { //权限判断,Xx某个属性
                return xx;
        }

案例练习:
​​​​
创建程序,在其中定义两个类: Account和AccountTest类 体会Java的封装性。
1. Account类要求具有属性: 姓名(长度为2位3位或4位)、余额(必须>20)、密码(必须是六位),如果不满足,则给出提示信息,并给默认值(程序员自己定)
2. 通过setXxx的方法给Account的属性赋值。
3. 在AccountTest中测试

package com.zakedu.encap;
 /**
 *创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
*Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、
*密码(必须是六位),如果不满足,则给出提示信息,并给默认值(程序员自己定)
 *通过setXxx的方法给Account的属性赋值。
*在AccountTest中测试 
*/
 public class Account {
 //为了封装,将3个属性设置为private
 private String name;
 private double balance;
 private String pwd;
 //提供两个构造器
public Account() {
 }
 public Account(String name, double balance, String pwd) {
 this.setName(name);
 this.setBalance(balance);
 this.setPwd(pwd);
 }
 public String getName() {
 return name;
 }
 //姓名(长度为2位3位或4位)
public void setName(String name) {
 if (name.length() >= 2 && name.length() <= 4) {
 this.name = name;
 } else {
System.out.println("姓名要求(长度为 2 位 3 位或4位),默认值 无名");
 this.name = "无名";
 }}

 public double getBalance() {
 return balance;
 }
 //余额(必须>20)
 public void setBalance(double balance) {
 if (balance > 20) {
 this.balance = balance;
 } else {
 System.out.println("余额(必须>20) 默认为 0");
 } }

 public String getPwd() {
 return pwd;
 }
 //密码(必须是六位)
public void setPwd(String pwd) {
 if (pwd.length() == 6) {
 this.pwd = pwd;
}else{
 System.out.println("密码(必须是六位)默认密码为000000");
 this.pwd="000000";
 }
 }
 //显示账号信息
public void showInfo(){
 //可以增加权限的校验
System.out.println("账号信息name="+name+"余额="+balance+"密码"+pwd);
 // if(){
 // System.out.println("账号信息name="+name+"余额="+balance+"密码");
 // }else{
 // System.out.println("你无权查看...");
 // }
} }

 package com.zakedu.encap;
 public class TestAccount{
 public static void main(String[]args){
 //创建Account
 Account account =new Account();
 account.setName("jack");
 account.setBalance(60);
 account.setPwd("123456");
 account.showInfo();
 } }

2. 继承

2.1 继承基本介绍

        继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。

2.2 继承的基本语法

继承给编程带来的便利:
        1) 代码的复用性提高了         2) 代码的扩展性和维护性提高了

2.3 继承的细节问题

1) 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
2) 子类必须调用父类的构造器,完成父类的初始化
3) 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
4) 如果希望指定去调用父类的某个构造器,则显式的调用一下:super(参数列表)
5) super在使用时,必须放在构造器第一行 (super只能在构造器中使用)
6) super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
7) java所有类都是Object类的子类,Object是所有类的基类.
8) 父类构造器的调用不限于直接父类!将一直往上追溯直到Object类(顶级父类)
9) 子类最多只能继承一个父类(指直接继承),即java中是单继承机制。
10) 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

2.4 继承的本质分析:

案例:

 public class ExtendsTheory {
 public static void main(String[] args) {
 Son son = new Son();//内存的布局
//?-> 这时请大家注意,要按照查找关系来返回信息
//(1) 首先看子类是否有该属性
//(2) 如果子类有这个属性,并且可以访问,则返回信息
//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
System.out.println(son.name);//返回就是大头儿子
//System.out.println(son.age);//返回的就是 39
//System.out.println(son.getAge());//返回的就是 39
 System.out.println(son.hobby);//返回的就是旅游
}}

 class GrandPa { //爷类
String name = "大头爷爷";
Stringhobby="旅游";
 }
 classFatherextendsGrandPa{//父类
Stringname="大头爸爸";
 privateintage=39;
 publicintgetAge(){
 returnage;
 } }
 classSonextendsFather{//子类
Stringname="大头儿子";
 }

3. super关键字

3.1 基本介绍

super代表父类的引用,用于访问父类的属性、方法、构造器

3.2 基本语法

1. 访问父类的属性,但不能访问父类的private属性
        super . 属性名;
2. 访问父类的方法,不能访问父类的private方法
        super . 方法名(参数列表);
3. 访问父类的构造器:
        super(参数列表) ;  // 只能放在构造器的第一句,只能出现一句!

3.3 super 给编程带来的便利

1. 调用父类的构造器的好处 (分工明确,父类属性由父类初始化,子类的属性由子类初始化)
2. 当子类中有和父类中的成员 (属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果!
3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员; 如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则

3.4 super 和 this 的比较

4. 方法重写/覆盖

4.1 基本介绍

        简单的说: 方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法

4.2 注意事项

方法重写也叫方法覆盖,需要满足下面的条件:

1. 子类的方法的 形参列表,方法名称, 要和父类方法的 形参列表,方法名称 完全一样。
2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
        比如 父类返回类型是Object,子类方法返回类型是String
        public object getInfo(){ }       与          public String getInfo(){ }
3. 子类方法不能缩小父类方法的访问权限
        public > protected >默认>private
        void sayok(){  }                public void sayok(){ }

重写和重载比较:

5. 多态

5.1 多[多种]态[状态]基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

5.2 多态的具体体现

5.2.1 方法的多态

重写和重载就体现多态
案例:

publicclassPloyMethod{
publicstaticvoidmain(String[]args){
 //方法重载体现多态
Aa=newA();
 //这里我们传入不同的参数,就会调用不同sum方法,就体现多态
System.out.println(a.sum(10,20));
 System.out.println(a.sum(10,20,30));
 //方法重写体现多态
Bb=newB();
 a.say();
 b.say();
}}
classB{//父类
publicvoidsay(){
 System.out.println("Bsay()方法被调用...");
 } }
classAextendsB{//子类
publicintsum(intn1,intn2){//和下面sum构成重载
returnn1+n2;
 }
 publicintsum(intn1,intn2,intn3){
 returnn1+n2+n3;
 }

 publicvoidsay(){
 System.out.println("Asay()方法被调用...");
 }}

5.2.2 对象的多态(核心,困难,重点)

(1) 一个对象的编译类型和运行类型可以不一致
(2) 编译类型在定义对象时,就确定了,不能改变
(3) 运行类型是可以变化的.
(4) 编译类型看定义时 =号的左边,运行类型看 =号的右边
案例:

package com.zakedu.poly_.objectpoly_;
public class Animal{
 public void cry(){
 System.out.println("Animalcry()动物在叫....");
 }}

 package com.zakedu.poly_.objectpoly_;
 public class Cat extends Animal{
 public void cry(){
 System.out.println("Catcry()小猫喵喵叫...");
 }}

 package com.zakedu.poly_.objectpoly_;
 public class Dog extends Animal{
  public void cry(){
 System.out.println("Dogcry()小狗汪汪叫...");
 }}

 packagecom.zakedu.poly_.objectpoly_;
 public class PolyObject{
 public static void main(String[]args){
 //体验对象多态特点
//animal编译类型就是Animal,运行类型Dog
 Animal animal = newDog();
 //因为运行时,执行到改行时,animal运行类型是Dog,所以cry就是Dog的cry
 animal.cry();//小狗汪汪叫
//animal编译类型Animal,运行类型就是Cat
 animal = new Cat();
 animal.cry();//小猫喵喵叫
}}

5.3 多态注意事项

多态的前提是:两个对象(类)存在继承关系
多态的向上转型:

多态向下转型:

packagecom.zakedu.poly_.detail_;
public class Animal{
 String name="动物";
 intage=10;
 public void sleep(){
 System.out.println("睡");
 }
 public void run(){
 System.out.println("跑");
}
 public void eat(){
 System.out.println("吃");
 }
 public void show(){
 System.out.println("hello,你好");
 }}

 package com.zakedu.poly_.detail_;
 public class Cat extends Animal {
 public void eat(){//方法重写
System.out.println("猫吃鱼");
 }
 public void catchMouse(){//Cat 特有方法
System.out.println("猫抓老鼠");
 } }

 package com.zakedu.poly_.detail_;
 public class Dog extends Animal {//Dog 是 Animal 的子类
}

 package com.zakedu.poly_.detail_;
 public class PolyDetail {
public static void main(String[] args) {
 //向上转型: 父类的引用指向了子类的对象
//语法:父类类型引用名 =new 子类类型();
 Animal animal = new Cat();
 Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类
//向上转型调用方法的规则如下:
 //(1)可以调用父类中的所有成员(需遵守访问权限)
 //(2)但是不能调用子类的特有的成员
//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
//animal.catchMouse();错误
//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
//,然后调用,规则我前面我们讲的方法调用规则一致。
animal.eat();//猫吃鱼..
 animal.run();//跑
animal.show();//hello,你好
animal.sleep();//睡

//可以调用Cat的 catchMouse方法
//多态的向下转型
//老师希望,可以调用Cat的 catchMouse方法
//(1)语法:子类类型 引用名 =(子类类型)父类引用;
 //问一个问题?cat 的编译类型 Cat,运行类型是 Cat
 Cat cat = (Cat) animal;
 cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
Dog dog=(Dog)animal;//可以吗?
System.out.println("ok~~");
 } }

属性没有重写之说!属性的值看编译类型:

 packagecom.zakedu.poly_.detail_;
 public class PolyDetail02{
 public static void main(String[]args){
 //属性没有重写之说!属性的值看编译类型
Base base = new Sub();//向上转型
System.out.println(base.count);//?看编译类型10
 Sub sub = new Sub();
 System.out.println(sub.count);//? 20
 } }
 class Base{//父类
int count=10;//属性
}
 class Sub extends Base{//子类
int count=20;//属性
}

instanceOf 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型:

package com.zakedu.poly_.detail_;
 public class PolyDetail03 {
 public static void main(String[] args) {
 BB bb = new BB();
 System.out.println(bb instanceof BB);// true
 System.out.println(bb instanceof AA);// true
 //aa 编译类型 AA, 运行类型是BB
 //BB 是AA子类
AA aa = new BB();
 System.out.println(aa instanceof AA);
 System.out.println(aa instanceof BB);
 Object obj = new Object();
 System.out.println(obj instanceof AA);//false
 String str = "hello";
 //System.out.println(str instanceof AA);
 System.out.println(str instanceof Object);//true
 } }

class AA{} //父类
class BB extends AA{}//子类

5.4 java 的动态绑定机制(非常非常重要.)

5.5 多态的应用

5.5.1 多态数组:

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

应用实例:
        现有一个继承结构如下:要求创建1个Person对象、2个Student对象和2个Teacher对象,统一放在数组 中,并调用每个对象say方法.
        应用实例升级:如何调用子类特有的方法,比如 Teacher有一个teach,Student有一个study 怎么调用?
代码:

 package com.zakedu.poly_.polyarr_;
 public class Person{//父类
 private String name;
 private int age;
 public Person(Stringname,intage){
 this.name=name;
 this.age=age;
 }
 public String getName(){
 return name;
 }
 public voidsetName(String name){
 this.name=name;
 }
 public int getAge(){
 return age;
 }
 public void setAge(intage){
 this.age=age;
 }
 public String say(){//返回名字和年龄
return name+"\t"+age;
 } }


 packagecom.zakedu.poly_.polyarr_;
 public class Student extends Person{
 private double score;
 public Student(String name,int age,double score){
 super(name, age);
 this.score = score;
 }
 public double getScore() {
 return score;
 }
 public void setScore(double score) {
 this.score = score;
 }
 //重写父类say
 @Override
 public String say() {
 return "学生 " + super.say() + " score=" + score;
 }
 //特有的方法
public void study() {
 System.out.println("学生 " + getName() + " 正在学 java...");
 } }

 package com.zakedu.poly_.polyarr_;
 public class Teacher extends Person {

private double salary;
 public Teacher(String name, int age, double salary) {
 super(name, age);
 this.salary = salary;
 }
 public double getSalary() {
 return salary;
 }
 public void setSalary(double salary) {
 this.salary = salary;
 }
 //写重写父类的say方法
@Override
 public String say() {
 return "老师 " + super.say() + " salary=" + salary;
 }
 //特有方法
public void teach() {
 System.out.println("老师 " + getName() + " 正在讲 java 课程...");
 } }
package com.zakedu.poly_.polyarr_;
 public class PloyArray {
 public static void main(String[] args) {
 //应用实例:现有一个继承结构如下:要求创建1个Person对象、
// 2 个Student 对象和2个Teacher 对象, 统一放在数组中,并调用每个对象say方法
Person[] persons = new Person[5];
 persons[0] = new Person("jack", 20);
 persons[1] = new Student("mary", 18, 100);
 persons[2] = new Student("smith", 19, 30.1);
 persons[3] = new Teacher("scott", 30, 20000);
 persons[4] = new Teacher("king", 50, 25000);
 //循环遍历多态数组,调用say
 for (int i = 0; i < persons.length; i++) {
 System.out.println(persons[i].say());//动态绑定机制
//老师提示:person[i] 编译类型是 Person,运行类型是是根据实际情况有JVM来判断
//这里大家聪明. 使用 类型判断 + 向下转型.
 if(persons[i] instanceof Student) {//判断 person[i] 的运行类型是不是 Student
 Student student = (Student)persons[i];//向下转型
 student.study();
 //小伙伴也可以使用一条语句 ((Student)persons[i]).study();
 } else if(persons[i] instanceof Teacher) {
 Teacher teacher = (Teacher)persons[i];
 teacher.teach();
} else if(persons[i] instanceof Person){
 //System.out.println("你的类型有误, 请自己检查...");
 } else {
 System.out.println("你的类型有误, 请自己检查...");
 } } } }

5.5.2 多态参数

代码:

 package com.zakedu.poly_.polyparameter_;
 public class Employee {
 private String name;
 private double salary;
 public Employee(String name, double salary) {
 this.name = name;
 this.salary = salary;
 }
 //得到年工资的方法
public double getAnnual() {
 return 12 * salary;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public double getSalary() {
 return salary;
 }
 public void setSalary(double salary) {
 this.salary = salary;
} }


 package com.zakedu.poly_.polyparameter_;
 public class Manager extends Employee{
 private double bonus;
 public Manager(String name, double salary, double bonus) {
 super(name, salary);
 this.bonus = bonus;
 }
 public double getBonus() {
 return bonus;
 }
 public void setBonus(double bonus) {
 this.bonus = bonus;
 }
 public void manage() {
 System.out.println("经理 " + getName() + " is managing");
 }
 //重写获取年薪方法
@Override
public double getAnnual(){
 returnsuper.getAnnual()+bonus;
 } }


 packagecom.zakedu.poly_.polyparameter_;
 public class Worker extends Employee{
 public Worker(Stringname,doublesalary){
 super(name,salary);
 }
 public void work(){
 System.out.println("普通员工"+getName()+"isworking");
 }
 @Override
 public double getAnnual(){//因为普通员工没有其它收入,则直接调用父类方法
return super.getAnnual();
 } }


packagecom.zakedu.poly_.polyparameter_;
 public class PloyParameter{
 public static void main(String[]args){
 Worker tom=new Worker("tom",2500);
Manager milan = new Manager("milan", 5000, 200000);
 PloyParameter ployParameter = new PloyParameter();
 ployParameter.showEmpAnnual(tom);
 ployParameter.showEmpAnnual(milan);
 ployParameter.testWork(tom);
 ployParameter.testWork(milan);
 }
 //showEmpAnnual(Employee e)
 //实现获取任何员工对象的年工资,并在main方法中调用该方法 [e.getAnnual()]
 public void showEmpAnnual(Employee e) {
 System.out.println(e.getAnnual());//动态绑定机制.
 }
 public void testWork(Employee e) {
 if(e instanceof Worker) {
 ((Worker) e).work();//有向下转型操作
} else if(e instanceof Manager) {
 } else {
 //添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法
((Manager) e).manage();//有向下转型操作
System.out.println("不做处理...");
 } } }

6. Object类详解

6.1 equals方法

== 和 equals的对比 (面试题):
==是一个比较运算符
1. ==:既可以判断基本类型,又可以判断引用类型;
2. ==:如果判断基本类型,判断的是值是否相等。示例: int i=10; double d=10.0;
3. ==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象;
4. equals:是Object类中的方法,只能判断引用类型;
5. 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如
lnteger,String【看看String和Integer的equals源代码】。
代码:

publicclassEquals01{
public static void main(String[]args){
 A a = new A();
 A b=a;
 A c=b;
 System.out.println(a==c);//true
 System.out.println(b==c);//true
 B bObj =a;
 System.out.println(bObj==c);//true
 int num1 =10
 double num2 = 10.0;
 System.out.println(num1 == num2);//基本数据类型,判断值是否相等
//equals 方法,源码怎么查看.
 //把光标放在equals 方法,直接输入ctrl+b
 //如果你使用不了. 自己配置. 即可使用.


 /*
 //带大家看看Jdk的源码 String类的 equals方法
//把 Object 的 equals 方法重写了,变成了比较两个字符串值是否相同
public boolean equals(Object anObject) {
 if (this == anObject) {//如果是同一个对象
return true;//返回 true
 }
 if (anObject instanceof String) {//判断类型
String anotherString = (String)anObject;//向下转型
int n = value.length;
 if (n == anotherString.value.length) {//如果长度相同
char v1[] = value;
 int i = 0;
 char v2[] = anotherString.value;
 while (n-- != 0) {//然后一个一个的比较字符
if (v1[i] != v2[i])
 return false;
 i++;
 }
return true;//如果两个字符串的所有字符都相等,则返回true
 }
 }
 return false;//如果比较的不是字符串,则直接返回false
 }
 */
 "hello".equals("abc");
 //看看Object 类的 equals 是
/*
 //即 Object 的 equals 方法默认就是比较对象地址是否相同
//也就是判断两个对象是不是同一个对象.
 public boolean equals(Object obj) {
 return (this == obj);
 }
 */
 /*
 //从源码可以看到 Integer 也重写了Object的equals方法,
 //变成了判断两个值是否相同
public boolean equals(Object obj) {
 if (obj instanceof Integer) {
 return value == ((Integer)obj).intValue()
}
 return false;
 }
 */
 Integer integer1 = new Integer(1000);
 Integer integer2 = new Integer(1000);
 System.out.println(integer1 == integer2);//false
 System.out.println(integer1.equals(integer2));//true
 String str1 = new String("hspedu");
 String str2 = new String("hspedu");
 System.out.println(str1 == str2);//false
 System.out.println(str1.equals(str2));//true
 }}

 class B {}
 class Aextends B {}

6.2 如何重写equals方法

应用实例: 判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之false。

 public class EqualsExercise01 {
 public static void main(String[] args) {
 Person person1 = new Person("jack", 10, '男');
 Person person2 = new Person("jack", 20, '男');
 System.out.println(person1.equals(person2));//假
}
 }
 //判断两个Person对象的内容是否相等,
//如果两个Person对象的各个属性值都一样,则返回true,反之false
 class Person{ //extends Object
 private String name;
 private int age;
 private char gender;
 //重写Object 的 equals 方法
public boolean equals(Object obj) {
 if(this == obj) {
 //判断如果比较的两个对象是同一个对象,则直接返回true
 return true;
 }
 //类型判断
if(obj instanceof Person) {//是 Person,我们才比较
//进行 向下转型, 因为我需要得到obj的 各个属性
Person p = (Person)obj;
 return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
 }
 //如果不是Person ,则直接返回false
 return false;
 }
 public Person(String name, int age, char gender) {
 this.name = name;
 this.age = age;
 this.gender = gender;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public int getAge() {
 return age;
}
 public void setAge(intage){
 this.age=age;
 }
 public char getGender(){
 return gender;
 }
 public void setGender(chargender){
 this.gender=gender;
 } }

6.3 hashCode 方法

6个小结:
1) 提高具有哈希结构的容器的效率!
2) 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
3) 两个引用,如果指向的是不同对象,则哈希值是不一样的
4) 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址。
5)案例演示[HashCode_.java]:obj.hashCode() [测试:Aobj1=newA();Aobj2=newA();Aobj3=obj1]
代码:

public class HashCode_{
 public static void main(String[]args){
 AA aa= new AA();
 AA aa2= new AA();
 AA aa3=aa;
 System.out.println("aa.hashCode()="+aa.hashCode());
 System.out.println("aa2.hashCode()="+aa2.hashCode());
 System.out.println("aa3.hashCode()="+aa3.hashCode());
 } }
 class AA{}

6.4 toString方法

1. 基本介绍:
默认返回:全类名+@+哈希值的十六进制,【查看Object的toString方法】 子类往往重写toString方法,用于返回对象的属性信息
2.  重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式
3.  当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用 monster.toString()
代码:

 public class ToString_ {
 public static void main(String[] args) {
 /*
 Object 的 toString() 源码
(1)getClass().getName() 类的全类名(包名+类名 )
 (2)Integer.toHexString(hashCode()) 将对象的 hashCode 值转成 16 进制字符串
public String toString() {
 return getClass().getName() + "@" + Integer.toHexString(hashCode());
 }
 */
 Monster monster = new Monster("小妖怪", "巡山的", 1000);
 System.out.println(monster.toString() + " hashcode=" + monster.hashCode());
 System.out.println("==当直接输出一个对象时,toString 方法会被默认的调用==");
 System.out.println(monster); //等价 monster.toString()
} }

 class Monster {
 private String name;
 private String job;
 private double sal;
 public Monster(String name, String job, double sal) {
 this.name = name;
 this.job = job;
 this.sal = sal;
 }
 //重写toString 方法, 输出对象的属性
//使用快捷键即可 alt+insert-> toString
 @Override
 return "Monster{" +
 "name='" + name + '\' +
 public String toString() { //重写后,一般是把对象的属性值输出,当然程序员也可以自己定制
", job='" + job + '\' +
 ", sal=" + sal +
 '}';
 }
 @Override
protectedvoidfinalize()throwsThrowable{
 System.out.println("fin..");
 } }

6.5 finalize方法

1) 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作
2) 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用finalize方法。
3) 垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制,测 试:Car[name]
提示:我们在实际开发中,几乎不会运用finalize,所以更多就是为了应付面试.
代码:
 

//演示Finalize的用法
public class Finalize_{
 public static void main(String[]args){
 Car bmw =new Car("宝马");
 //这时car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象,在销毁对象前,会调用该对象的finalize方法
//,程序员就可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
 //,如果程序员不重写finalize,那么就会调用Object类的finalize,即默认处理
//,如果程序员重写了finalize, 就可以实现自己的逻辑
 bmw =null;
 System.gc();//主动调用垃圾回收器
System.out.println("程序退出了....");
 } }

 class Car {
 private String name;
 //属性, 资源。。
public Car(String name) {
 this.name = name;
 }
 //重写finalize
 @Override
 protected void finalize() throws Throwable {
 System.out.println("我们销毁 汽车" + name );
 System.out.println("释放了某些资源...");
 } }

7. 断点调试(debug)

7.1 断点调试介绍

1. 断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。进行分析从而找到这个Bug
2. 断点调试是程序员必须掌握的技能。
3. 断点调试也能帮助我们查看java底层源代码的执行过程,提高程序员的Java水平。

7.2 断点调试的快捷键

F7(跳入) F8(跳过) shift+F8(跳出)F9(resume,执行到下一个断点)
F7:跳入方法内
F8: 逐行执行代码.
shift+F8: 跳出方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1633281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Stable Diffusion 模型分享:Counterfeit-V3.0(动漫)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 高质量动漫风格模型。 条目内容类型大模型基础模…

(十三)Servlet教程——Servlet中Cookie的使用

1.什么是Cookie Cookie意为甜饼&#xff0c;最早由Netscape社区发展的一种机制。目前Cookie已经成为标准&#xff0c;所有的主流浏览器都支持Cookie。 由于HTTP是一种无状态的协议&#xff0c;服务器仅从网络连接上无法知道客户身份。于是就客户端颁发一个通行证&#xff0c;无…

SpringBoot框架学习笔记(一):依赖管理和自动配置

本文为个人笔记&#xff0c;仅供学习参考之用&#xff0c;如有不当之处请指出。 本文基于springboot2.5.3版本&#xff0c;开发环境需要是 jdk 8 或以上&#xff0c;maven 在 3.5 1 SpringBoot 基本介绍 1.1 官方文档 &#xff08;1&#xff09; 官网 : https://spring.io/pr…

虚函数表与虚函数表指针

虚函数表与虚函数表是用来实现多态的&#xff0c;每一个类只有一个虚函数表 静态多态&#xff1a;函数重载&#xff08;编译期确定&#xff09; 动态多态&#xff1a;虚函数&#xff08;运行期确定&#xff09; 虚函数表的创建时机&#xff1a; 生成时间&#xff1a; 编译期…

交换排序-冒泡排序 快速排序

目录 3.1 冒泡排序 3.2 快速排序 Hoare版本快速排序 挖坑法快速排序 前后指针法快速排序 快速排序优化-三数取中法 快速排序非递归 3.1 冒泡排序 思想&#xff1a;升序情况下&#xff1a;左边大于右边就进行交换&#xff0c;每一次把最大的放在最后一位。 void Swap(int…

【Unity100个实用小技巧】Unity接入微信SDK

前言 为了实现Unity接入微信排行榜,记录一下&#xff0c;为了以后用&#xff0c;本篇文章是对于使用中的一些疑惑点记录。完整流程官方和下面链接都有&#xff0c;补充一些&#xff0c;其他文档中未提到的。 步骤 必要步骤 一. 微信转小游戏 勾选 【使用好友关系链】 二. 看下…

(06)vite与ts的结合

文章目录 系列全集package.json在根目录创建 tsconfig.json 文件在根目录创建 vite.config.ts 文件index.html额外的类型声明 系列全集 &#xff08;01&#xff09;vite 从启动服务器开始 &#xff08;02&#xff09;vite环境变量配置 &#xff08;03&#xff09;vite 处理 c…

基于springboot+vue+Mysql的时间管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

基于双层优化的电动汽车优化调度研究(附matlab程序)

基于双层优化的电动汽车优化调度研究 0.代码链接 基于双层优化的电动汽车优化调度研究(matlab程序)资源-CSDN文库 1.简述 关键词&#xff1a;双层优化 选址定容 输配协同 时空优化 参考文档&#xff1a;《考虑大规模电动汽车接入电网的双层优化调度策略_胡文平》…

机器学习-11-卷积神经网络-基于paddle实现神经网络

文章目录 总结参考本门课程的目标机器学习定义第一步&#xff1a;数据准备第二步&#xff1a;定义网络第三步&#xff1a;训练网络第四步&#xff1a;测试训练好的网络 总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍基于paddle实现神经网络。 参考 MNIST 训练_副…

C# Form1.cs 控件全部丢失的问题解决

在应用C#开发程序时&#xff0c;代码写了一堆&#xff0c;等调试时&#xff0c;点开 Form1.cs窗体时&#xff0c;出现如下提示。点击忽略并继续是&#xff0c;整个窗体控件全部丢失。 初次遇到这个问题&#xff0c;很容易进入到误区&#xff0c;以为窗体控件真的全部丢失了&am…

算法入门ABC

前言 初学算法时真的觉得这东西晦涩难懂&#xff0c;貌似毫无用处&#xff01;后来的后来&#xff0c;终于渐渐明白搞懂算法背后的核心思想&#xff0c;能让你写出更加优雅的代码。就像一首歌唱的那样&#xff1a;后来&#xff0c;我总算学会了如何去爱&#xff0c;可惜你早已远…

Linux磁盘分区与管理

标题日期版本说明署名 Linux磁盘分区与管理 2024.4.29 v0.0.0*******LGB 目标&#xff1a;能够熟练掌握Linux系统磁盘分区管 操作系统&#xff1a;Centos Stream 9 实验过程&#xff1a; 1.首先我们先新建一块磁盘。 2.我们先对新建磁盘进行分区。 3.输入n 创建分区&#xf…

Llama3 在线试用与本地部署

美国当地时间4月18日&#xff0c;Meta 开源了 Llama3 大模型&#xff0c;目前开源版本为 8B 和 70B 。Llama 3 模型相比 Llama 2 具有重大飞跃&#xff0c;并在 8B 和 70B 参数尺度上建立了 LLM 模型的新技术。由于预训练和后训练的改进&#xff0c;Llama3 模型是目前在 8B 和 …

React、React Router 和 Redux 常用Hooks 总结,提升您的开发效率!

Hooks 是 React 16.8 中引入的一种新特性&#xff0c;它使得函数组件可以使用 state 和其他 React 特性&#xff0c;从而大大提高了函数组件的灵活性和功能性。下面分别总结React、React Router 、Redux中常用的Hooks。 常用Hooks速记 React Hooks useState&#xff1a;用于…

vue为遍历生成的表单设置ref属性

最近在写表单重置的时候出现了问题&#xff0c;在this.$refs[formName].resetFields();的时候卡了很久。 经过网上的搜索终于解决的问题&#xff01; 对于不需要遍历的表单 这是vue代码&#xff1a; <el-dialog title"段落描述" :visible.sync"dialogFormV…

流水线工作流程

java编译命令&#xff1a; java -jar xxx.jar (其它参数已忽略) docker镜像构建命令&#xff1a; docker build -t [镜像名称:latest] -f 指定[Dockerfile] [指定工作目录] 推送镜像 jenkinsfile: 主要流程登录镜像仓库&#xff0c;打包镜像&#xff0c;推送到镜像仓库

MySql 主从同步-在原来同步基础上增加历史数据库

在MySql已经主从同步的后&#xff0c;由于有新的需求再增加1个历史数据库&#xff0c;要改原来的1个变成现在的2个数据库。在官网并没有找到类似的场景&#xff08;官方同步多个数据是从一开始就设置&#xff0c;不是后续增加的&#xff09;&#xff0c;只能结合以往的经验自己…

第三方软件测试机构-科技成果评价测试

科技成果评价测试是对科研成果的工作质量、学术水平、实际应用和成熟程度等方面进行的客观、具体、恰当的评价过程。这一评价过程有助于了解科技成果的质量和水平&#xff0c;以及其在学术和应用方面的价值和潜力。 科技成果评价测试主要包括以下几个方面&#xff1a; 工作质量…

OpenVoice: Versatile Instant Voice Cloning

OpenVoice&#xff1a;多功能即时语音克隆 摘要 OpenVoice是一种多功能的即时声音克隆方法&#xff0c;它只需要参考说话者的一小段音频就可以复制他们的声音并以多种语言生成语音。OpenVoice 在解决以下领域中的开放性挑战方面代表了重大进展&#xff1a;1) 灵活的声音风格控…