七 面向对象(中级)

这里写目录标题

  • 1.包
    • 1.1包的命名
    • 1.2Java中常用包
    • 1.3细节
  • 2.访问修饰符
  • 3.封装
    • 3.1构造器与setXxx结合
  • 4.继承
    • 4.1细节
    • 4.2练习
  • 5.super关键字
    • 5.1细节
    • 5.2super和this的比较
  • 6.方法重写/覆盖
    • 6.1重载和重写的区别
  • 7.多态
    • 7.1向上转型
    • 7.2向下转型
    • 7.3instanceOf比较操作符
    • 7.4Java动态绑定机制
    • 7.5多态数组
    • 7.6多态参数
  • 8.Object类
    • 8.1equals方法
    • 8.2自己重写equals方法
    • 8.3hashCode方法
    • 8.4toString方法
    • 8.5finalize方法
  • 9.断点调试(debug)

1.包

1.包的作用:

①区分相同名字的类

②当类很多时,可以更好的管理类

③控制访问范围

package 包名

包的本质创建不同的文件夹来保存类文件
在这里插入图片描述
在这里插入图片描述

1.1包的命名

规则:包含数字,字母,下划线,小圆点,不
能以数字开头,不能是关键字或保留字

规范:小写字母➕小圆点
com.公司名.项目名.业务模块名

1.2Java中常用包

java.lang*:基本包,默认引入

java.util.*:工具包,工具类(Scanner)

java.net*:网络包,网络开发

java.awt*:Java的页面开发,GUI

import java.util.Scanner;
//只会引入java.util包下的Scanner(推荐)
import java.util.*;
//把java.util包下的所有类都引入


import java.util.Arrays;

int[] arr = {9,68,8,102,46};
Arrays.sort(arr);//自动排序

for(int i;i < arr.length;i++){
   System.out.print(arr[i] + " ");
   //输出8 9 46 68 102
}

1.3细节

1.package语句放在最上面,一个类中最多只有一句package

2.import放在package下面,在类定义前,可以有多句,没有顺序要求

2.访问修饰符

用于控制方法和属性的使用权限

1.public:公共级别,对外公开

2.protected:受保护级别,对子类和同一个包中的类公开

3.默认:向同一个包中的类公开

4.private:只有类本身可以访问,不对外公开
在这里插入图片描述
可以修饰属性和方法,只有public和默认可以修饰类

面向对象的三大特征:封装,继承,多态

3.封装

把属性和方法封装在一起,通过授权方法来操作

好处:①隐藏实现细节②可以对数据进行验证,保证安全合理

步骤:
①将属性进行私有化private

②提供一个公共的set方法,用于对属性判断并赋值

public void setXxx(类型 参数名){
       //Xxx表示某个属性
      //加入数据验证的业务逻辑
      属性 = 参数名;
}

③提供一个公共的get方法,用于获取属性的值

public 数据类型 getXxx(){//权限判断
    return xx;
}

3.1构造器与setXxx结合

import java.util.*;

/*
不能随便查看人的年龄,工资
年龄在1-120岁之间,否则给999
工资不能直接查看
name的长度在2-6个字符之间
*/

public class t1封装信息 {  
  public static void main(String[] args) {    
    Person p = new Person();    
    p.setName("Jack");    
    p.setAge(45);    
    p.setSal(5000);    
    System.out.println(p.info());    
    System.out.println(p.getSal());  
    
    Person p1= new Person("张三",580,6000);
    System.out.println(p1.info());
  }
} 
class Person{    
  public String name;    
  private int age;    
  private double sal;  
  
  public Person(){
  }    
  //构造器与setXxx结合
  public Person(String name,int age,double sal){        
    setName(name);        
    setAge(age);        
    setSal(sal);    
  }
  //姓名      
  public String getName(){        
    return name;    
  }    
  public void setName(String name){        
    if(name.length() >= 2 && name.length() <= 6){            
      this.name = name;        
    }else{            
      System.out.println("名字长度在2-6个字符之间");            
      this.name = "无";        
    }    
  }    
  //年龄
  public int getAge(){        
    return age;    
  }    
  public void setAge(int age){        
    if(age >= 1 && age <= 120){            
      this.age = age;        
    }else{            
      System.out.println("年龄在1-120岁之间");            
      this.age = 999;        
    }    
  }    
  //工资
  public double getSal(){        
  //判断信息是否正确        
    return sal;    
  }    
  public void setSal(double sal){        
    this.sal = sal;    
  }    
  //输出
  public String info(){        
    return "姓名:" + name + "年龄:" + age + "工资:" + sal;    
  }
}

4.继承

class 子类 extends 父类{
}

在这里插入图片描述
便利:①代码复用性,扩展性,维护性提高

4.1细节

1.子类继承了父类所有的属性和方法,私有属性和方法不能在子类直接访问,要通过父类提供的公共方法去访问

2.子类必须调用父类的构造器,完成对父类的初始化

public class Test{
  public static void main(String[] args) {
    C c = new C();  
    c.say();
  }
}

public class C extends F{
  C(){
    System.out.println("子类构造器被调用");
  }
  public void say(){    
    System.out.println(n1 + " " + n2 + " " + n3);    
    System.out.println(getN4());    
    test100();    
    test200();    
    test300();    
    sayOk();  
  }
}

public class F{
  public int n1 = 100;
  protected int n2 = 200;
  int n3 = 300;
  private int n4 = 400;

  F(){
    System.out.println("父类构造器被调用");
  }
  public int getN4(){
  //通过父类提供的公共方法去访问
    return n4;
  }
  public void test100(){
    System.out.println("test100");
  }
  protected  void test200(){
    System.out.println("test200");  
  }
  void test300(){
    System.out.println("test300");  
  }
  private void test400(){
    System.out.println("test400");  
  }
  public void sayOk(){
  //通过父类提供的公共方法去访问
    test400();
  }
}

3.当创建子类对象时,不管使用子类的哪个对象,都会调用父类的无参构造器;如果父类没有无参构造器,则必须在子类的构造器中用super()去指定使用父类的哪个构造器,否则,编译不通过

4.要指定调用父类的某个构造器,super(实参)

5.super()和this()放在构造器第一行,且两个方法不能在同一个构造器

6.super只能在构造器中使用

7.Object是所有类的父类

8.子类只能直接继承一个父类,Java是单继承

public class C{
  C(){
    super(60);
  }
}
public class F{
  F(int age){
  }
}

先加载父类
在这里插入图片描述

4.2练习

class A{
  A(){
    System.out.println("a");
  }
  A(String name){
    System.out.println("a name");
  }
}

class B extends A{
  B(){
    this("abc");//调用B的有参构造器
    System.out.println("b"); 
  }
  B(String name){
  //有隐藏的super();调用父类无参构造器
    System.out.println("b name");
  }
}

B b = new B();//调用无参构造器
//结果:a,b name,b

5.super关键字

代表父类的引用,用于访问父类的属性,方法,构造器,但不能访问父类的private

访问属性:super.属性名;

访问方法:super.方法名(参数列表);

访问构造器:super(参数列表;)

5.1细节

1.好处:分工明确,父类属性由父类初始化,子类属性由子类初始化

2.当子类和父类成员重名时,访问父类成员,必须用super,没有重名,则super,this,直接访问都一样

5.2super和this的比较

在这里插入图片描述

6.方法重写/覆盖

1.子类方法的参数列表和名称和父类完全一样

2.子类方法的返回类型和父类方法的返回类型一致,或是父类返回类型的子类

3.子类方法不能缩小父类方法的访问权限

public class C extends F{
  public void cry(){
  //方法重写
  //父类是public,子类就不能是protected,默认,private
    System.out.println("喵喵叫...");
  }
  public String m1(){
  //String是Object的子类
    return null;
  }
  
  public A m2(){
  //返回类型和父类完全一致
    return null;
  }
  public B m2(){
  //B是父类返回类型的子类
    return null;
  }
}
public class F{
  public void cry(){
    System.out.println("旺旺叫...");
  }
  public Object m1(){
    return null;
  }
  
  public A m2(){
    return null;
  }
}

class A{

}
class B extends A{

}

6.1重载和重写的区别

在这里插入图片描述

7.多态

方法或对象具有多种形态,前提是双方存在继承关系,建立在封装和继承基础之上

方法的多态:重载和重写

对象的多态:

1.编译类型 = 运行类型

2.一个对象的编译类型和运行类型可以不一致

3.编译类型在定义对象时就确定了

4.运行类型是可以变化的

//Dog和Cat继承了Animal类
Animal animal = new Dog();
/*
Animal是Dog的父类
父类的引用指向子类的对象,子类的对象可以赋给父类的引用
编译类型是Animal,运行类型是Dog
*/
animal = new Cat();
//编译类型仍然是Animal,运行类型变成了Cat

7.1向上转型

父类的引用指向子类的对象

父类类型 引用名 = new 子类类型();

可以调用父类的所有成员,不可以调用子类的特有成员

7.2向下转型

子类类型 引用名 = (子类类型) 父类引用;

1.只能强转父类的引用,不能强转父类的对象

2.父类的引用必须指向当前目标类型的对象

3.可以调用子类类型所有成员

public class T{
  Cat cat = new Cat ();
  Animal a = cat;
  //向上转型,把子类的引用赋给父类的引用
  Animal animal = new Cat();
  Object obj = new Cat();//Object是超类
  //向上转型
  
  animal.sleep();//睡
  animal.eat();//吃鱼
  //animal.show();不可以,show是子类的特有方法
}
  Cat cat = (Cat) animal;
  //编译类型是Cat,运行类型是Cat
  //只能强转父类的引用
  //animal指向了Cat的对象
  cat.show();

class Cat extends Animal{
  public void eat(){
    System.out.println("吃鱼");
  }
  public void show(){
  System.out.println("展示");
  }
}

public class Animal{
  public void sleep(){
    System.out.println("睡");
  }
  class void eat(){
   System.out.println("吃");
  }
}

属性没有重写,看编译类型

F f = new C();
System.out.println(c.count);//10
//编译类型是F

public class F{
  int count = 10;
}
class C extends F{
  int count = 20;
}

7.3instanceOf比较操作符

判断对象的运行类型是否为XX类型或XX类型的子类

C c = new C();
System.out.println(c instanceof F);//true
F f = new C();
System.out.println(f instanceof F);//true
String str = "hello"
System.out.println(str instanceof Object);//true  运行类型是String

class C extends F{
}
public class F{
}
Object obj = "hello";
//向上转型  Object obj = new String("hello");

Object object = new Integer(5);//向上转型
//父类引用指向Integer
String str = (String) object;//不可以
//指向Integer的父类引用转成String
//父类引用必须指向当前目标类型的对象
Integer str1 = (Integer) object;

属性看编译类型,方法看运行类型

Sub s = new Sub();
Base b =s;
//向上转型,把子类的引用赋给父类的引用
System.out.println(b == s);//true
System.out.println(b.count);//10
//属性看编译类型,编译类型是Base
b.display();//20
//方法看运行类型,运行类型是Sub
class Sub extends Base{
  int count = 20
  public void display(){
    System.out.println(this.count);
  }
}
public class Base{
  int count = 10;
  public void display(){
    System.out.println(this.count);  
  }
}

7.4Java动态绑定机制

1.调用对象方法时,会和该对象的内存地址(运行类型)绑定

2.调用对象属性时,没有动态绑定机制,哪里声明哪里调用

A a = new B();
System.out.println(a.sum());//30
/*
1.在B类里找sum()方法,没找到
2.在A类里找sum()方法,找到了
3.返回getI() + 10;
4.调用了getI()方法,和运行类型绑定
5.在B类里找getI()方法
6.返回i,i = 20
7.所以20 + 10 = 30
*/
System.out.println(a.sum1());//20
/*
1.在B类里找sum1()方法,没找到
2.在A类里找sum1()方法,找到了
3.返回i + 10;
4.属性i没有动态绑定机制,所以i是A类里的
5.i = 10,返回10 + 10 = 20
*/

class B extends A{
  public int i = 20;
  
  public int getI(){    
    return i;  
  }
}
public class A{
  public int i = 10;
  public int sum(){
    return getI() + 10;
  }
  public int sum1(){
    return i + 10;
  }
  public int getI(){
    return i;
  }
}

7.5多态数组

数组的定义类型为父类类型,里面的元素为子类类型

/*
Student,Teacher继承Person
stu为Student特有方法
tea为Teacher特有方法
*/

Person[] p = new Person[5];
p[0] = new Student("张三",18,69.5);   
p[1] = new Student("李四",18,78.9);    
p[2] = new Teacher("Tom",36,8000);    
p[3] = new Teacher("Jary",40,6000);   
p[4] = new Person("王五",36);     

//输出
for(int i = 0;i < p.length;i++){        
  System.out.println(p[i].say());
} 
//输出其特有方法
for(int i = 0;i < p.length;i++) {
  if(p[i] instanceof Student){            
    Student s = (Student)p[i];            
    s.stu();        
  }else if(p[i] instanceof Teacher){            
    Teacher t = (Teacher)p[i];             
    t.tea();        
  }else if(p[i] instanceof Person){                    

  }else{            
    System.out.println("错误❌");        
  }    
}

7.6多态参数

方法定义的形参类型为父类,实参类型为子类

/*
Common,Manager继承Employee
Employee有getAnnual方法,输出一年工资
Common,Manager重写getAnnual方法
work为Common特有方法
manage为Manager特有方法
*/

public class test {
  public static void main(String[] args) {    
    Employee e = new Employee();    
    Common c = new Common("张三",2000);    
    Manager m = new Manager("李四",5000,1000);     
       
    test t = new test();    
    //多态参数
    t.showEmpAnnual(c);//传入子类,向上转型    
    t.testWork(c);//传入子类,向上转型      
  }  
  
  public void showEmpAnnual(Employee e){//父类      
    System.out.println(e.getAnnual());  
  }  
  public void testWork(Employee e){//父类      
    if(e instanceof Common){          
      ((Common) e).work();//向下转型,调用子类特有类      
    }else if(e instanceof Manager){           
      ((Manager) e).manage();      
    }  
  }
}

8.Object类

8.1equals方法

==是比较运算符,可以判断基本类型,引用类型

基本类型:判断值是否相等

引用类型:判断地址是否相等,即判定是否为同一个对象

A a = new A();
A b = a;
A c = b;
System.out.println(a == c);//true

B obj = a;//父类的引用指向子类的对象
System.out.println(obj == c);//true

class A extends B{}
public class B{}

equals:Object类中的方法,只能判断引用类型

默认判断是地址是否相等,子类中往往重写该方法,用于判断内容是否相等

Integer integer1 = new Integer(10000);
Integer integer2 = new Integer(10000);
System.out.println(integer1 == integer2);//flase
//不是同一个对象
System.out.println(integer1.equals(integer2));//true
//默认判断是地址是否相等,子类中往往重写该方法,用于判断内容是否相等

8.2自己重写equals方法

import java.util.*;
/*
判断两个Person对象的内容是否相等
如果两个Person对象的各个属性值相同,返回true
否则返回flase
*/

public class t4子类重写equals方法 {   
  public static void main(String[] args) {    
    Person2 p01 = new Person2("张三",18,'男');    
    Person2 p02 = new Person2("张三",18,'男');    
    System.out.println(p01.equals(p02));  
  }
}
class Person2{    
  private String name;    
  private int age;    
  private char gender;//gender表示性别        
  Person2(String name,int age,char gender){        
    this.name = name;        
    this.age = age;        
    this.gender = gender;    
  }    
  public boolean equals(Object obj){        
    if(this == obj){            
    //当前和传入相等            
      return true;        
    }        
    if(obj instanceof Person2){            
      //传入的对象是否为Person2类            
      Person2 p03 = (Person2)obj;            
      //向下转型,要得到传入类的属性            
      return this.name.equals(p03.name) && this.age == p03.age && this.gender == p03.gender;        
    }        
    //如果不是Person2类,直接返回false        
    return false;    
  }    
  public String getName(){        
    return name;    
  }    
  public void setName(){        
    this.name = name;    
  }    
  public int getAge(){        
    return age;    
  }    
  public void setAge(){        
    this.age = age;    
  }    
  public char getGender(){        
    return gender;    
  }    
  public void setGender(){        
    this.gender = gender;    
  }
}

8.3hashCode方法

1.提高具有哈希容器的效率

2.两个引用,指向同一个对象,哈希值肯定一样,指向不同对象,哈希值是不同的

3.哈希值主要根据地址号来的,不能完全将哈希值等价于地址

4.在集合中,hashCode如果需要,也会重写

A a1 = new A();
A a2 = new A();
A a3 = a1;
System.out.println(a1.hashCode());
System.out.println(a2.hashCode());
System.out.println(a3.hashCode());
//a1和a3是一样的
class A{}

8.4toString方法

默认返回全类名 + @ + 哈希值的十六进制

子类往往会重写toString方法,用于返回对象的属性信息

//Object的toString原码
public String toString(){
  return getClass().getName() + '@' + Integer.toHexString(hashCode());
  //getClass().getName()表示全类名,包名+类名
  //Integer.toHexString(hashCode());将对象的hashCode值转成十六进制字符串
}
A a = new A("Tom",18);
System.out.println(a.toString());
//由于A类中没有重写,所以调用的是Object类中的toString方法

//重写toString方法,用于返回对象的属性信息
//alt + insert → toString
public String toString(){
  return "对象的属性信息";
}

当直接输出一个对象时,toString方法会被默认调用

System.out.println(person);
//默认调用person.toString()

8.5finalize方法

1.当方法被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作

2.当某个对象没有任何引用时,就会被回收,在销毁该对象前,会先调用finalize方法

3.垃圾回收机制的调用,是由系统自己来决定的,也可以通过System.cg();主动触发垃圾回收机制

A a = new A(10);
a = null;
//这时A对象就是一个垃圾
System.cg();
//主动调用垃圾回收器
System.out.println("输出...");//先输出
/*
输出...
完成...
*/

class A{
  private int age;
  A(int age){
   this.age = age;
  }
  public void finalize() throws Throwable{
    System.out.println("完成...");
  }
}

9.断点调试(debug)

以对象的运行类型来执行

1.F7: 跳入方法内

2.F8: 跳过,逐行执行代码

3.shift + F8: 跳出方法

4.F9: 执行到下一个断点
在这里插入图片描述
查看jdk源码
在这里插入图片描述

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值