day07 7.1 Java中的面向对象之类与对象

发布时间 2023-07-16 15:23:03作者: Chimengmeng

day07 7.1 Java中的面向对象之类与对象

【一】类与对象

【1】类定义规范

  • 类与对象的关系
    • 类 是实体对象的概念模型,笼统的,不具体的,
      • 比如人类、动物类、鸟类
    • 对象 又称为实体,类具体化的表现
      • 小红/小明
      • 小猫一号/小狗一号
    • 对象中有属性,有方法
      • 不同对象属性是独有的
      • 方法是共有的
  • 类定义规范
// [] :内的内容可以不写  | :左右的内容表示或

[public][abstract|final] class 类名class_name [extends 继承的类名] [implements 实现的接口名]{
    // 定义成员属性
    属性类型1 属性名1; // String name;
    属性类型2 属性名2; // int age;
        
    // 定义静态属性(类属性)
    private String name;
        
    // 定义类成员方法
    public int add(int a, int b){
        return a+b;
    }
    
    // 定义静态方法(类方法)
    public static void speak(){
        System.out.println("说话")
    }
}

public:表示类是公有的

java文件的文件名必须是public class 类名

abstract:抽象类

final:类如果被 final 修饰 ,这个类不能被别的类所继承

extends:继承某个父类

implements:实现的接口

(1)类的定义

public class Person {
    // 定义成员属性
    private String name;
    // 定义成员属性
    public int age;
    // 定义静态属性
    public static int sex;

    // 定义类成员方法
    // void:方法没有返回值
    public void speak() {
        System.out.println("说话了!");
    }

    // 静态方法
    public static run() {
        System.out.println("跑起来了!");
    }

}

(2)对象的实例化

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

public class Demo01 {

    public static void main(String[] args) {
        // 因为在同一个包下,所以可以直接引用
        // (1)实例化类对象 p
        Person p = new Person();

        // (2)修改对象属性
        // 由于 name 是由 private 修饰
        // 所以无法通过对象 修改该属性
        p.age = 18;
        System.out.println(p);
        // Person@1b6d3586
        
        // (3)调用对象方法
        p.speak();
        // 说话了!
    }
}

【2】Java的类属性

  • 在类中有属性
    • 成员属性
      • 只要不被static修饰的,就是成员属性,他是属于对象的,需要对象来调用
    • 静态变量
      • 只要 static修饰的,需要类或类实例的对象来调用
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

//public class Demo01 {
//
//    public static void main(String[] args) {
//        // 因为在同一个包下,所以可以直接引用
//        // (1)实例化类对象 p
//        Person p = new Person();
//
//        // (2)修改对象属性
//        // 由于 name 是由 private 修饰
//        // 所以无法通过对象 修改该属性
//        p.age = 18;
//        System.out.println(p);
//        // Person@1b6d3586
//
//        // (3)调用对象方法
//        p.speak();
//        // 说话了!
//    }
//}

public class Demo01 {

    public static void main(String[] args) {
        // 类属性

        // (1)实例化类得到类对象
        Person p = new Person();
        // 对象的属性 ----> 不被static修饰的
        p.hobby = "music";
        p.age = 18;

        Person p1 = new Person();
        // 对象的属性 ----> 不被static修饰的
        p1.hobby = "sport";
        p1.age = 29;

        // 每个对象都有自己的属性,因此打印的内容不一样
        System.out.println(p.hobby);
        System.out.println(p1.hobby);

        // (2)静态成员:被static修饰的,属于类
        // 通过对象,修改静态成员,但是他是属于类的,都会受影响
        p.sex = 2;
        p1.sex = 1;
        System.out.println(p.sex);
        // 2
        // 1
        System.out.println(p1.sex);
        // 2
        // 1

        // 类来修改静态属性,一般是用类来修改静态属性
        Person.sex = 3;
        System.out.println(p.sex);
        // 3
        System.out.println(p1.sex);
        // 3

    }
}
public class Person {
    // 定义成员属性
    private String name;
    // 定义成员属性
    public String hobby;
    public int age;
    // 定义静态属性
    public static int sex;

    // 定义类成员方法
    // void:方法没有返回值
    public void speak() {
        System.out.println("说话了!");
    }

    // 静态方法
    public static void run() {
        System.out.println("跑起来了!");
    }

}

  • 在Python中年对象的属性只能对象来调用
  • 在Python中年类的属性只能类来调用

【3】成员方法

  • 类中没有被static修饰的方法,绑定给类的,需要类来调用。
  • Python中有绑定给对象的方法,绑定给类的方法

    • Python的类中,不加任何装饰器的的方法是绑定给对象的

      java:public void Speak(){}
      
    • Python的类中,使用@classmethod修饰的,是绑定给类的方法

      java:public static void Speak(){}
      

public class Demo01 {

    public static void main(String[] args) {
        // 静态方法和成员方法
        Person p = new Person();

        p.speak(); // 对象的方法
        
//        p.run();//类的方法,正常不是对象来调用,而是类来调用
        Person.run();

    }
}
public class Person {
    // 定义成员属性
    private String name;
    // 定义成员属性
    public String hobby;
    public int age;
    // 定义静态属性
    public static int sex;

    // 定义类成员方法
    // void:方法没有返回值
    // 没有被 static 修饰
    public void speak() {
        System.out.println("说话了!");
    }

    // 静态方法
    // 被 static 修饰
    public static void run() {
        System.out.println("跑起来了!");
    }

}

【4】构造方法

  • 在Python中

    __init__方法完成对象的初始化

  • 在Java中

    完成对对象的初始化,向对象中添加内容

    可以存在多个,使用哪种初始化方式,就会触发那种构造方法

public class Demo01 {

    public static void main(String[] args) {
        // 构造方法

        // (1)触发无参构造方法
        Person person = new Person();
        // 实例化对象,但是不向对象中添加参数
        // 会触发Person类的无参构造方法,完成初始化
        // 一旦执行,person中的 name 就完成了初始化 变成了 dream
        System.out.println(person.name);
        // 我正在开始执行!
        // dream

        // (2)触发有参构造方
        Person p = new Person("mengmeng");
        System.out.println(p.name);
        // 我是有参构造方法,形参为1个
        // mengmeng

        // (3)触发有参构造方法
        Person p1 = new Person("CHIMENG", 19);
        System.out.println(p1.name);
        System.out.println(p1.age);
        // 我是有参构造方法,形参为2个
        // CHIMENG
        // 19



    }
}
public class Person {
    // 定义成员属性
//    private String name;
    // 定义成员属性
    public String hobby;
    public String name;
    public int age;
    // 定义静态属性
    public static int sex;

    // 定义类成员方法
    // void:方法没有返回值
    // 没有被 static 修饰
    public void speak() {
        System.out.println("说话了!");
    }

    // 静态方法
    // 被 static 修饰
    public static void run() {
        System.out.println("跑起来了!");
    }

    // 构造方法
    // 无参构造方法
    public Person() {
        System.out.println("我正在开始执行!");
        this.name = "dream";
    }

    // 有参构造方法
    public Person(String name) {
        System.out.println("我是有参构造方法,形参为1个");
        this.name = name;
    }

    // 有参构造方法
    public Person(String name, int age) {
        System.out.println("我是有参构造方法,形参为2个");
        this.name = name;
        this.age = age;
    }
}

【5】this关键字

  • this是写在类中的成员(对象)方法中
  • [static修饰的方法中,即静态方法中,没有this]
public class Demo01 {

    public static void main(String[] args) {
        // 构造方法

        // (1)触发无参构造方法
        Person person = new Person();
        // 实例化对象,但是不向对象中添加参数
        // 会触发Person类的无参构造方法,完成初始化
        // 一旦执行,person中的 name 就完成了初始化 变成了 dream
        System.out.println(person.name);
        // 我正在开始执行!
        // dream

        // (2)触发有参构造方
        Person p = new Person("mengmeng");
        System.out.println(p.name);
        // 我是有参构造方法,形参为1个
        // mengmeng

        // (3)触发有参构造方法
        Person p1 = new Person("CHIMENG", 19);
        System.out.println(p1.name);
        System.out.println(p1.age);
        // 我是有参构造方法,形参为2个
        // CHIMENG
        // 19

        // this 触发
        // 谁调用方法就是谁
        person.Sleep();
        //dream
        //睡觉中.....
        p.Sleep();
        //mengmeng
        //睡觉中.....
        p1.Sleep();
        //CHIMENG
        //睡觉中.....

    }
}
public class Person {
    // 定义成员属性
//    private String name;
    // 定义成员属性
    public String hobby;
    public String name;
    public int age;
    // 定义静态属性
    public static int sex;

    // 定义类成员方法
    // void:方法没有返回值
    // 没有被 static 修饰
    public void speak() {
        System.out.println("说话了!");
    }

    // 静态方法
    // 被 static 修饰
    public static void run() {
        System.out.println("跑起来了!");
    }

    // 构造方法
    // 无参构造方法
    public Person() {
        System.out.println("我正在开始执行!");
        this.name = "dream";
    }

    // 有参构造方法
    public Person(String name) {
        System.out.println("我是有参构造方法,形参为1个");
        this.name = name;
    }

    // 有参构造方法
    public Person(String name, int age) {
        System.out.println("我是有参构造方法,形参为2个");
        this.name = name;
        this.age = age;
    }

    // this 关键字
    public void Sleep() {
        System.out.println(this.name);
        System.out.println("睡觉中.....");
    }    

}

【6】访问控制符

访问范围 private friendly(默认) protected public
同一个类 可访问 可访问 可访问 可访问
同一包中的其他类 不可访问 可访问 可访问 可访问
不同包中的子类 不可访问 不可访问 可访问 可访问
不同包中的非子类 不可访问 不可访问 不可访问 可访问
//1  private
用 private 修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用。因此,private 修饰符具有最高的保护级别
  
//2 friendly(默认)
如果一个类没有访问控制符,说明它具有默认的访问控制特性。这种默认的访问控制权规定,该类只能被同一个包中的类访问和引用,而不能被其他包中的类使用,即使其他包中有该类的子类。这种访问特性又称为包访问性(package private)

//3  protected
用保护访问控制符 protected 修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类。使用 protected 修饰符的主要作用,是允许其他包中它的子类来访问父类的特定属性和方法,否则可以使用默认访问控制符。
  
//4 public
当一个类被声明为 public 时,它就具有了被其他包中的类访问的可能性,只要包中的其他类在程序中使用 import 语句引入 public 类,就可以访问和引用这个类

【7】静态变量和静态方法(static)

在类中,使用static修饰的变量是属于类的,正常类来调用,但是对象也可以调用

在类中,使用static修饰的方法是属于类的,正常类来调用,不需要实例化,就能调用,但是对象也可以调用,但是他的内部没有this关键字

什么情况下定义对象的方法[成员方法]

什么情况下定义类的方法[静态方法]

以后,不想初始化得到对象就能使用这个方法,就定义成静态方法。

(1)什么是静态变量(类变量)

  • 在类中,使用 static 修饰符修饰的属性(成员变量)称为静态变量,也可以称为类变量
    • 常量称为静态常量
    • 方法称为静态方法或类方法
  • 它们统称为静态成员,归整个类所有。
    • 静态成员不依赖于类的特定实例,被类的所有实例共享
    • 就是说 static 修饰的方法或者变量不需要依赖于对象来进行访问
    • 只要这个类被加载,Java 虚拟机就可以根据类名找到它们

(2)什么是静态变量

  • 类的成员变量可以分为以下两种:
    • 静态变量(或称为类变量),指被 static 修饰的成员变量
    • 实例变量,指没有被 static 修饰的成员变量
  • 静态变量与实例变量的区别如下:

  • 1)静态变量

    • 运行时,Java 虚拟机只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配

    • 在类的内部,可以在任何方法内直接访问静态变量

    • 在其他类中,可以通过类名访问该类中的静态变量

  • 2)实例变量

    • 每创建一个实例,Java 虚拟机就会为实例变量分配一次内存

    • 在类的内部,可以在非静态方法中直接访问实例变量

    • 在本类的静态方法或其他类中则需要通过类的实例对象进行访问

(3)什么是静态方法

  • 类的成员方法也可以分为以下两种:
    • 静态方法(或称为类方法),指被 static 修饰的成员方法
    • 实例方法,指没有被 static 修饰的成员方法
  • 静态方法与实例方法的区别如下:
    • 静态方法不需要通过它所属的类的任何实例就可以被调用
    • 因此在静态方法中不能使用 this 关键字,也不能直接访问所属类的实例变量和实例方法
    • 但是可以直接访问所属类的静态变量和静态方法。
    • 另外和 this 关键字一样, super 关键字也与类的特定实例相关
    • 所以在静态方法中也不能使用 super 关键字
    • 在实例方法中可以直接访问所属类的静态变量、静态方法、实例变量和实例方法

【二】面向对象之继承

【1】继承格式

  • 在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:

    class 父类 {
    }
     
    class 子类 extends 父类 {
    }
    class 子子类 extends 子类 {
    }
    
  • Java中的继承

    • 只支持单继承,不支持多继承,但支持实现多个接口
    • 支持一条线上的多重继承
  • Java不支持多继承,但是可以通过接口来实现多继承的功能

【2】构造方法

(1)分文件继承

  • 构造Animal类
public class Animal {
    String name;
}
  • 构造Dog类
public class Dog  extends Animal {
    int age;
    // 有参构造
    public Dog(String name,int age){
        this.name = name;
        this.age = age;

    }
}
  • 实例化调用
public class Demo01 {

    public static void main(String[] args) {
        // 继承的关系测试

        // 实例化得到一个DOG对象
        // Dog = new Dog(); // 没有参数传入会报错,因为Dog内部是一个有参构造方法
        Dog d = new Dog("dream", 18);
        System.out.println(d.name); // dream

    }
}

(2)单文件继承

在一个文件中只能有一个 public 方法

class Animal {
    String name;
}

class Dog  extends Animal {
    int age;
    // 有参构造
    public Dog(String name,int age){
        this.name = name;
        this.age = age;

    }
}

public class Demo01 {

    public static void main(String[] args) {
        // 继承的关系测试

        // 实例化得到一个DOG对象
        // Dog = new Dog(); // 没有参数传入会报错,因为Dog内部是一个有参构造方法
        Dog d = new Dog("dream", 18);
        System.out.println(d.name); // dream

    }
}

(3)小结

  • 子类如果没写构造方法
    • 默认使用父类无参构造
  • 本案例名字为:固定名字
// 1 子类如果没写构造方法,默认使用父类无参构造,本案例名字为:固定名字
// 2 子类如果没写构造方法,不会自动使用父类的有参构造,所以Person p=new Person("justin");用法是报错的
import java.util.*;


public class Demo04 {
    public static void main(String[] args) throws Exception {

        Person p=new Person("justin");
        p.Speak();
        System.out.println(p.name);

    }

}

class Animal{
    String name;
    public Animal(){
        this.name="固定名字";
    }
    public Animal(String  name){
        this.name=name;
    }

    public void Speak(){
        System.out.println("动物说话");

    }
}

class Person extends Animal {
    int age;
    // 子类如果没写构造方法,默认使用父类无参构造,本案例名字为:固定名字
    // 子类如果没写构造方法,不会自动使用父类的有参构造,所以Person p=new Person("justin");用法是报错的
    //    public Person(String name,int age){
    //        this.name=name;
    //        this.age=age;
    //    }
    public void Run(){
        System.out.println("人走路");
    }

    @Override
    public void Speak(){
        super.Speak(); // 代指父类对象,等同于python的super()
        System.out.println("人说话");

    }
}

【3】super 与 this 关键字

有了继承关系就会多了另一个关键字(原来有this):super(等同于python中的super())

  • super关键字:
    • 我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类
  • this关键字:指向自己的引用
class Animal{
    String name;
    public void Speak(){
        System.out.println("动物说话");

    }
}
class Person extends Animal {
    int age;
    public void Run(){
        System.out.println("人走路");
    }

    @Override
    public void Speak(){
        this.Speak(); // 代指自己的,先从自己找,自己没有去父类找
        super.Speak(); // 代指父类对象,等同于python的super(),直接去父类找
        System.out.println("人说话");

    }
}

【三】重写(Override)与重载(Overload)

【1】什么是重写

  • 重写(Override)是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。
  • 即外壳不变,核心重写

【2】什么是重载

  • 重载(overloading) 是在一个类里面,方法名字相同,而参数不同。

  • 返回类型可以相同也可以不同

  • 被重载的方法必须改变参数列表(参数个数或类型不一样)

【3】演示

class Animal{
    String name;
    public Animal(){
        this.name="固定名字";
    }
    public Animal(String  name){
        this.name=name;
    }

    public void Speak(){
        System.out.println("动物说话");

    }
}
class Person extends Animal {
    int age;
    public void Run(){
        System.out.println("人走路");
    }
    // 重载方法 - 方法名一样,参数不一样
    public void Run(String ss){
        System.out.println(ss);
        System.out.println("走路");
    }
    // 重写方法Speak - 必须有继承关系
    @Override
    public void Speak(){
        super.Speak(); // 代指父类对象,等同于python的super()
        System.out.println("人说话");
    }

    // 重载方法Speak
    public void Speak(String aa){
        super.Speak(); // 代指父类对象,等同于python的super()
        System.out.println("人说话");

    }
}

【四】面向对象之接口

【1】接口的介绍

(1)接口是一个抽象类型

  • 接口(Interface),是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。
  • 一个类通过继承接口的方式,从而来继承接口的抽象方法。

只在接口中定义某个方法,可以不写这个方法,意思是继承接口的类必须要有我定义的接口中的方法

(2)接口并不是类

  • 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。
  • 类描述对象的属性和方法。接口则包含类要实现的方法。

(3)接口无法被实例化,但是可以被实现

  • 一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
  • 接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

接口不支持被 new

(4)接口与类相似点

  • 一个接口可以有多个方法
  • 接口文件保存在 .java 结尾的文件中,文件名使用接口名

(5)接口与类的区别

  • 接口不能用于实例化对象
  • 接口没有构造方法
  • 接口中所有的方法必须是抽象方法
  • 接口不能包含成员变量,除了 static 和 final 变量
  • 接口不是被类继承了,而是要被类实现
  • 接口支持多继承
    • 类可以实现多个接口

【2】接口声明

  • 定义接口语法
public interface 接口名 extends 其它接口 {
    // 声明变量 static 和 final 变量
    // 声明方法,抽象方法
    public Speak(); // 不用加{},这里只是定义了一个接口方法,而没有具体实现这个方法,所以不用加{}
}
  • 官方一点的写法
[可见度] interface 接口名称 [extends 其他的接口名] {
        // 声明变量
        // 抽象方法
}
  • 示例
  • 接口
interface Duck {
    //任何类型 final, static 字段
    final String name="dream";
    public static int age = 19;

    //抽象方法
    public void Speak();
    //public void Run(){}; // 不能有具体实现
    public void Run(); // 不能有具体实现
}
  • 子类中实现接口
// 子类实现接口,必须实现接口中所有的方法
class TDuck implements Duck {

    @Override
    public void Speak() {
        System.out.println("鸭子叫");
    }

    @Override
    public void Run() {
        System.out.println("鸭子走路");
    }
}
  • python中的鸭子类型
    • 只要我的方法中有这两个方法,就是同一类
class TDuck():
	def speak():
    	pass
    def run():
        pass

class RDuck():
	def speak():
    	pass
    def run():
        pass
  • Java中的鸭子类型
    • 在Java中必须实现继承的同一个接口的两个类才叫鸭子类型,是同一类
interface Duck {
    //任何类型 final, static 字段
    final String name = "dream";
    public static int age = 19;

    //抽象方法
    public void Speak();

    //public void Run(){}; // 不能有具体实现
    public void Run(); // 不能有具体实现
}

// 子类实现接口,必须实现接口中所有的方法
class TDuck implements Duck {

    @Override
    public void Speak() {
        System.out.println("唐老鸭鸭子叫");
    }

    @Override
    public void Run() {
        System.out.println("唐老鸭鸭子走路");
    }
}

class RDuck implements Duck {

    @Override
    public void Speak() {
        System.out.println("肉鸭鸭子叫");
    }

    @Override
    public void Run() {
        System.out.println("肉鸭鸭子走路");
    }
}

【3】接口继承

  • 可以继承多个接口
interface Duck {
    public void Speak();
    public void Run();
}

interface TDuck extends Duck{
    public void Flay();
}

// 接口的多继承:在Java中,类的多继承是不合法,但接口允许多继承。在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口
interface Foo extends Duck, TDuck{
}

【4】接口实现

  • 可以实现多个接口
// 实现接口,必须实现接口中所有的方法
interface Duck {
    //抽象方法
    public void Speak();
    public void Run(); // 不能有具体实现
}

interface TDuck extends Duck{
    public void Flay();
}
class RealDuck implements TDuck{

    @Override
    public void Speak() {
        
    }

    @Override
    public void Run() {

    }

    @Override
    public void Flay() {

    }
}

【五】面向对象之抽象类

  • 定义格式
public abstract class Foo{
    // 定义方法
    public void Speak(){
         System.out.println("Speak Speak Speak");
    }
    // 定义抽象方法
    public abstract void Sleep();
}

// 继承

class Bird extends Foo {
    // Speak 已经有具体实现了,可以不重写
    // 但是Sleep必须重写,因为没有实现
    @Override
    public void Sleep() {
        System.out.println("必须重写抽象方法");
    }
}
  • 案例演示
public class Demo04 {
    public static void main(String[] args) {
        Bird b = new Bird();
        b.Speak(); // Speak Speak Speak
        b.Sleep(); // 必须重写抽象方法
    }
}


abstract class Foo {
    // 定义方法
    public void Speak() {
        System.out.println("Speak Speak Speak");
    }

    // 定义抽象方法
    public abstract void Sleep();
}

// 继承
class Bird extends Foo {
    // Speak 已经有具体实现了,可以不重写
    // 但是Sleep必须重写,因为没有实现
    @Override
    public void Sleep() {
        System.out.println("必须重写抽象方法");
    }
}

【六】抽象类和接口的区别

【小结】

  • 关键字不一样

  • 类继承是 implements extends

  • 类是类,接口是接口

  • 抽象类中方法可以具体实现,但是接口不能有具体实现

  • 一个类可以实现多个接口,但是不能继承多个类

【详解】

  • 关键字不同:

    • 在Java中,使用abstract关键字定义抽象类

    • 使用interface关键字定义接口。

  • 形式上的区别:

    • 类可以继承一个类,但类不能继承多个类

    • 一个类可以实现多个接口。

  • 方法的实现:

    • 抽象类可以包含具体的方法实现

      • 这些方法可以被子类继承和重写,也可以直接被调用。
    • 接口只能定义方法的签名

      • 不能包含方法的实现,实现接口的类必须提供接口中定义的所有方法的具体实现。
  • 字段的定义:

    • 抽象类可以定义实例变量

      • 这些变量可以是任意的访问修饰符,并且可以有默认值。
    • 接口只能定义常量字段(static final

      • 而且字段默认为公共、静态和最终。
  • 设计思想:

    • 抽象类用于表示一种通用的父类

      • 其中包含了子类所共有的属性和方法。
    • 接口则用于定义一组行为和功能的规范

      • 不关心具体实现细节,只关注方法的输入和输出。
  • 总结来说
    • 抽象类更类似于普通类的扩展和继承
    • 接口更像是一种规范或者契约,用于描述类应该具有的行为和功能。
  • 在设计中,应根据具体的需求选择使用抽象类还是接口。
    • 如果需要表达一种"is-a"的关系并且需要共享代码实现
      • 可以使用抽象类;
    • 如果需要表达一种"has-a"的关系或者需要多继承
      • 可以使用接口。

【七】面向对象之封装

【1】面向对象三大特性

  • 继承

  • 多态

  • 封装

  • 封装

    • 把属性或方法放在类的内部,可以隐藏起来,然后拿到一个对象
    • 可以 .属性 .方法 进行使用

【2】在Java中,习惯把属性定义成私有的,然后提供方法,来进行读写

public class Demo05 {
    public static void main(String[] args) {
        // 实例化类对象
        Fish f = new Fish();
        f.name = "xxx"; // 这样做是不行的,因为类属性被定义为私有的属性,无法通过实例化对象调用去修改私有属性
    }
}

// 定义一个类
class Fish {
    // 类里面放了一个私有属性
    private String name;
}
  • 解决
public class Demo05 {
    public static void main(String[] args) {
        // 实例化类对象
        Fish f = new Fish();

        // 通过方法去修改设置属性 - 安全
        f.setName("小黄鱼");
        System.out.println(f.getName()); // 小黄鱼

    }
}

// 定义一个类
class Fish {
    // 类里面放了一个私有属性
    private String name;

    // Java 中习惯这样用
    // 开放接口方法,供外部修改调用
    public void setName(String name) {
        this.name = name;
    }

    // 开放接口方法,当外部访问时,可以将想要反出去内容返回
    public String getName() {
        return this.name;
    }

}
  • 支持自定义返回数据
public class Demo05 {
    public static void main(String[] args) {
        // 实例化类对象
        Fish f = new Fish();

        // 通过方法去修改设置属性 - 安全
        f.setName("小黄鱼");
        System.out.println(f.getName()); // 小黄鱼安全属性

    }
}

// 定义一个类
class Fish {
    // 类里面放了一个私有属性
    private String name;

    // Java 中习惯这样用
    // 开放接口方法,供外部修改调用
    public void setName(String name) {
        this.name = name;
    }

    // 开放接口方法,当外部访问时,可以将想要反出去内容返回
    public String getName() {
        // 支持返回的数据拼接其他的东西
        return this.name + "安全属性";
    }
}

【3】详解

// java中一般不直接通过对象调用属性,而是通过方法来设置和获取属性【更安全】
class Person {
    public String name ;
    private int age;
    public void setAge(int age){
        this.age=age;
    }
    public int getAge(){
        return this.age+1;
    }
}

【八】面向对象之多态

【1】什么是多态

  • 多态是同一类事物[实例,对象]多种形态
猫对象1号
狗对象1号
都属于动物类  --> 动物类(通过继承,实现多个接口),有多种具体形态
调用 同一类事物共有的方法 --> 虽然调用同样的方法,但是各自表现出来的不一样,狗是狗叫,猫是猫叫
  • 从而调用同一类[实例,对象]方法时,表现出不同

【2】多态存在的三个必要条件

  • (1)编写具有继承关系的父类和子类/接口实现
  • (2)子类重写父类方法
  • (3)使用父类的引用指向子类的对象
前面是父类 ---- 指向了具体的某一个类
Duck d = new Tduck()
	而不是
Tduck d = new Tduck()

【3】继承实现的多态

public class Demo06 {
    public static void main(String[] args) {
        // 多态
        // 实例化得到对象
        // 将具体的类赋值给父类
        Foo1 c1 = new Child1();
        Foo1 c2 = new Child2();

        // 调用方法
        c2.Run();
        c2.Speak();
        // c2.Sleep(); // c2是Foo1类型,Foo1没有 Sleep 方法,所以不能调用 Sleep 方法
        // 如果想调用必须要做类型转换
        Child2 cc2 = (Child2) c2;  // 强制转换数据类型
        cc2.Sleep(); // 转成具体类型,可以调用具体的独有的方法

        // c1 可以转换成 Child2 类型吗?
        // 不可以,每个对象有每个对象自己独有的类,不能将两个本质上不同的类强转成另一个类
        // 即 c1 本质上是 Child1 类型 , 不能强转成 Child2 类型

        // 强转类型建议加 If 判断
        if (c1 instanceof Child1) {
            Child1 cc1 = (Child1) c1;
        }


    }
}

// 定义父类
class Foo1 {
    public void Speak() {
        System.out.println("父类的Speak方法");
    }

    public void Run() {
        System.out.println("父类的Run方法");
    }
}

// 子类继承父类
class Child1 extends Foo1 {
    // 重写父类方法可以不写
    @Override
    public void Speak() {
        System.out.println("这是子类1中重写的 Speak 方法");
    }

    @Override
    public void Run() {
        System.out.println("这是子类1中重写的 Run 方法");
    }
}

class Child2 extends Foo1 {
    // 重写父类方法可以不写
    @Override
    public void Speak() {
        System.out.println("这是子类2中重写的 Speak 方法");
    }

    @Override
    public void Run() {
        System.out.println("这是子类2中重写的 Run 方法");
    }

    // 定义子类独有的方法
    public void Sleep() {  // 派生方法: 比父类方法多的方法叫派生方法
        System.out.println("这是子类2独有的 Sleep 方法");
    }
}
  • 子类转父类不叫强转,直接赋值给父类即可
  • 父类转子类需要强转,强转可能会出错

【4】其他知识详解

(1)多态成员变量编译运行看左边

public class Demo04 {
    public static void main(String[] args) throws Exception {
        // 1 多态成员变量:编译运行看左边
        Animal dog = new Dog();
        System.out.println(dog.age);
    }
}

//父类
class Animal {
    public int age = 11;
}
//子类
class Dog extends Animal {
    public int age = 33;

}

(2)多态成员方法:编译看左边,运行看右边

public class Demo04 {
    public static void main(String[] args) throws Exception {

        // 1 多态成员变量:编译运行看左边
        Animal dog = new Dog();
        System.out.println(dog.age);
        // 2 多态成员方法:编译看左边,运行看右边
        dog.eat();
    }
}

//父类
class Animal {
    public int age = 11;
    public void eat() {
        System.out.println("动物吃饭");
    }
}
//子类
class Dog extends Animal {
    public int age = 33;
    @Override
    public void eat() {
        System.out.println("狗吃饭");
    }
}

(3)子类增加独有方法walk()

import java.util.*;
import com.justin.*;
import com.justin.Db;
import com.justin.Helper;

public class Demo04 {
    public static void main(String[] args) throws Exception {

        // 1 多态成员变量:编译运行看左边
        Animal dog = new Dog();
        System.out.println(dog.age);

        // 2 多态成员方法:编译看左边,运行看右边
        dog.eat();
        // 3 无法调用子类独有方法
        //dog.walk();


    }
}

//父类
class Animal {
    public int age = 11;
    public void eat() {
        System.out.println("动物吃饭");
    }

}
//子类
class Dog extends Animal {
    public int age = 33;
    @Override
    public void eat() {
        System.out.println("狗吃饭");
    }
    public void walk() {
        System.out.println("狗走路");
    }

}

(4)引用类型转换

  • 1 向上转型:【儿子变父亲】
    • 多态本身是子类向父类向上转换(自动转换)的过程
    • 这个过程是默许的
    • 当父类引用指向一个子类对象时,就是向上转型
  • 2 向下转型:【父亲变儿子,需要强制转换】
    • 向下转型,强制类型转换
Dog dog1 = (Dog) dog;
dog1.walk();
  • 3 类型转换会出现【类型转换异常】
  • 4 instanceof 判断具体类型
import java.util.*;

import com.justin.*;
import com.justin.Db;
import com.justin.Helper;

public class Demo04 {
    public static void main(String[] args) throws Exception {

        // 强制类型转换会出错
        Animal cat = new Cat();
//        Dog d=(Dog)cat;
//        d.walk();

        // 通过instance判断再转
        if(cat instanceof Cat){
            Cat c=(Cat) cat;
            c.sleep();
        }



    }
}

//父类
class Animal {
    public int age = 11;

    public void eat() {
        System.out.println("动物吃饭");
    }


}

//子类
class Dog extends Animal {
    public int age = 33;

    @Override
    public void eat() {
        System.out.println("狗吃饭");
    }

    public void walk() {
        System.out.println("狗走路");
    }

}

class Cat extends Animal {
    public int age = 63;

    @Override
    public void eat() {
        System.out.println("猫吃饭");
    }

    public void sleep() {
        System.out.println("猫睡觉");
    }

}

(5)抽象类实现的多态

public class Demo04 {
    public static void main(String[] args) throws Exception {

        //  抽象类实现的多态
        Animal a=new Dog();
        a.eat();
        a.speak();

    }
}

//父类
abstract class Animal {
    abstract void speak();
    public void eat() {
        System.out.println("动物吃饭");
    }


}

//子类
class Dog extends Animal{
    // 必须重写虚类上的方法
    @Override
    void speak() {
        System.out.println("狗叫");
    }
}

(6)接口实现的多态

import java.util.*;

import com.justin.*;
import com.justin.Db;
import com.justin.Helper;

public class Demo04 {
    public static void main(String[] args) throws Exception {

        // 2 接口实现的多态
        Animal a=new Dog();
        a.speak();

    }
}


interface Animal {
    public void speak();

}

//子类
class Dog implements Animal{
    @Override
    public void speak() {
        System.out.println("狗叫");
    }
    public void eat() {
        System.out.println("狗吃");
    }
}

【九】枚举

  • Java 枚举是一个特殊的类,一般表示一组常量,
    • 一年的 4 个季节
    • 一年的 12 个月份
    • 性别有男,女,未知
import java.util.*;


public class Demo04 {
    public static void main(String[] args) throws Exception {
        // 1 简单使用
        System.out.println(Sex.Unknown);
        System.out.println(Sex.Male);

        // 2 更多使用
        System.out.println("枚举顺序值,"+Week.SUNDAY.ordinal());   // 0
        System.out.println(Week.MONDAY.id);
        System.out.println(Week.MONDAY.meaning);



    }

}

enum Sex {
    Male,
    Female,
    Unknown;
}

enum Week {
    SUNDAY(0, "星期日"),
    MONDAY(1, "星期一"),
    TUESDAY(2, "星期二"),
    WEDNESDAY(3, "星期三"),
    THURSDAY(4, "星期四"),
    FRIDAY(5, "星期五"),
    SATURDAY(6, "星期六");
    public int id;
    public String meaning;

    Week(int id, String meaning) {
        this.id = id;
        this.meaning = meaning;
    }
}

【十】包(package)

【1】什么是包

  • 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。

我们可以定义很多包

不同包下,类名可以重复

同一个包下,类名不能重复

【2】包的作用

  • 1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用

  • 2、同文件夹一样,包采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。

  • 3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

【3】创建包

// 右键,新建包----》其实就是文件夹
	com.dream
 
// 在包中定义类
com.dream
	Db.java
	Helper.java 
  • Helper.java
// 先声明是哪个包下的类(功能)
package com.dream;
public class Helper {
    public int add(int a ,int b){
        return a+b;

    }
}

【4】引入包,并使用包中的类

// 导入包下的所有类
import com.dream.*;

// 单独导入指定的包
import com.dream.Db;
import com.dream.Helper;

public class Demo04 {
    public static void main(String[] args) throws Exception {
        // 实例化的到dream类
        Helper h=new Helper();
        System.out.println(h.add(4,5));
    }
}