Java面向对象

面向对象编程

Java的核心思想就是OOP

初识面向对象

面向过程&面向对象

  • 面向过程思想(框架)

    线性思维 适合处理一些比较简单的问题

  • 面向对象思想(流程)

    物以类聚 分类的思维模式 适合处理需要多人合作的复杂问题

    属性+方法 - >类

什么是面向对象

  • 面向对象编程(Object-Oriented Programming,OOP)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
  • 抽象
  • 三大特性
    • 封装
    • 继承
    • 多态

回顾方法及加深

方法的定义

  • 修饰符

  • 返回类型

    package com.oop.demo01;
    
    public class Demo01 {
        public static void main(String[] args) {
    
        }
        /*
        修饰符 返回值类型 方法名(...){
        // 方法体
        return 返回值; return结束方法,返回一个结果
        }
        */
        public String sayHello() {
            return "Hello World";
        }
    
        public void sayHi() {
            System.out.println("Hi");
            return; // 也可以不写return
        }
    
        public int max(int a, int b) {
            return a > b ? a : b; // 三元运算符
        }
    
    }
    
    
  • break:跳出switch 结束循环 return:结束方法, 返回结果

  • 方法名: 驼峰 见名知意

  • 参数列表:参数类型,参数名

  • 异常抛出:后面讲解 例:数组下标越界:ArrayIndexOutOfBounds

    public void readFile(String file) throws IOException{
        
    }
    

方法的调用

  • 静态方法

    ![静态方法的调用](C:\Users\12113\Pictures\Screenshots\屏幕截图 2025-03-31 224430.png)

  • 非静态方法

    ![非静态方法的调用](C:\Users\12113\Pictures\Screenshots\屏幕截图 2025-03-31 224915.png)

    package com.oop.demo01;
    
    public class Demo02 {
    
    
        public static void main(String[] args) {
            //实例化这个类 new
            //对象类型 对象名字 = 对象值;
            Student student = new Student();
            student.say();
        }
        //static和类一起加载
        public static void a() {
           // b();// 报错 b前面加static 或者 把a前面的static删掉
        }
        //对象在类实例化之后才存在
        public void b() {
    
        }
    }
    
    
  • 形参和实参

    package com.oop.demo01;
    
    public class Demo03 {
        public static void main(String[] args) {
            //实参和形参的类型要对应
           int add = Demo03.add(1, 2);  //实参
           System.out.println(add);
    
        }
        public static int add(int a, int b) {   //形参
            return a + b;
        }
    }
    
    
  • 值传递和引用传递

    package com.oop.demo01;
    
    //值传递
    public class Demo04 {
        public static void main(String[] args) {
            int a = 1;
            System.out.println(a);
    
            Demo04.change(a);
            System.out.println(a);  //结果为1
        }
        //返回值为空
        public static void change(int a) {
            a = 10;
        }
    }
    
    
    package com.oop.demo01;
    //引用传递:对象 本质还是值传递
    
    public class Demo05 {
        public static void main(String[] args) {
            Person person = new Person();
            System.out.println(person.name);// null
            
            Demo05.change(person);
            System.out.println(person.name);// Arb
            
        }
        public static void change(Person person) {
            //person是一个对象,指向的--->Person person = new Person();这是一个具体的人,可以改变属性!
            person.name = "Arb";
        }
    }
    //定义了一个Person类,有一个属性:name
    class Person{
        String name;
    }
    
  • this关键字

类与对象

类与对象的创建

类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物

一个Java类里面可以有多个类,但是只能有一个public class

从本节开始要注意不要在每一个类中都定义一个main方法,可以直接创建一个主启动的class里面用main方法

package com.oop.demo02;

//学生类
public class Student {

    //属性:字段
    String name;    //默认为null
    int age;    //默认为0

    //方法
    public void study() {
        System.out.println(this.name+"在学习");
    }
}

package com.oop.demo02;

//一个项目应该只存一个main方法
public class Application {
    public static void main(String[] args) {

        //类是抽象的,要把类实例化
        //类实例化后会返回一个自己的对象
        //对象就是一个Student类的具体实例
        Student student1 = new Student();
        Student student2 = new Student();
        
        student1.name = "小明";
        student1.age = 3;

        System.out.println(student1.name);
        System.out.println(student1.age);

        student2.name = "小红";
        student2.age = 3;

        System.out.println(student2.name);
        System.out.println(student2.age);

    }
}

构造器详解(重要)

类中的构造器也称为构造方法

特点:1. 必须和类的名字相同 2.必须没有返回类型,也不能写void

默认的构造器例子

package com.oop.demo02;

public class Person {
//一个类就算什么都不写它也会存在一个方法,这个方法就是构造方法
}

package com.oop.demo02;


public class Application {
    public static void main(String[] args) {
        //使用new关键字实例化一个对象
        Person person = new Person();


    }
}

虽然不输出任何东西,但是仍然能运行,就是因为系统提供了一个默认的构造器如下:多了一个无方法体的方法

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.oop.demo02;

public class Person {
    public Person() {
    }
}

怎么知道默认构造器的内容呢?

  1. 点击IDEA右上角的设置标志
  2. 打开Project Structure
  3. 点击module 添加根目录
  4. 找到module directory中out文件
  5. apply后即可在视图中打开out里面所需的class文件

我们也可以自己显式定义构造器

package com.oop.demo02;

public class Person {
//一个类就算什么都不写它也会存在一个方法,这个方法就是构造方法
    //显式定义构造器
    String name;


    //无参构造:实例化初始值
    /*
    1.使用new关键字,本质是调用构造器
    2.用来初始化值
     */

    public Person() {
    }
    //有参构造:一旦定义了有参构造,无参构造就必须显式定义

    public Person(String name) {
        this.name = name;
    }
    //快捷键:alt + insert 选择constructor
}

package com.oop.demo02;


public class Application {
    public static void main(String[] args) {
        //使用new关键字实例化一个对象
        Person person = new Person("Arb");	//new的时候有参,调用的就是有参构造器

        System.out.println(person.name);
    }
}

创建对象内存分析

![](C:\Users\12113\Pictures\Camera Roll\微信图片_20250408230738.jpg)

封装

该暴露的暴露,该隐藏的隐藏 高内聚低耦合

属性私有,get/set

作用:

  1. 提高程序的安全性,保护数据
  2. 隐藏代码的实现细节
  3. 统一接口
  4. 系统的可维护性增加
package com.oop.demo04;

public class Student {

    //属性私有
    //名字
    private String name;
    //学号
    private int id;
    //性别
    private char gender;
    //年龄
private int age;
    //提供一些可以操作这个属性的方法!
    //提供一些public的get/set方法

    //get 获得这个数据
    public String getName() {
        return this.name;
    }
    //set 给这个数据设置值
    public void setName(String name) {
        this.name = name;
    }

//alt+insert 快速生成get/set


    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age < 0 || age > 200) {
            age = 0;
        }
        else {
            this.age = age;
        }
    }
}

package com.oop;

import com.oop.demo03.Pet;
import com.oop.demo04.Student;

public class Application {
    public static void main(String[] args) {
        Student s1 = new Student();//使用ctrl + alt +v 自动补全前面的代码 使用alt+enter可将提示快速显示出来

        s1.setName("John");
        System.out.println(s1.getName());

        s1.setAge(999);
        System.out.println(s1.getAge());
    }
}

继承

什么是继承

继承的本质是对类的抽象

继承是类与类之间的一种关系

Java中只有单继承没有多继承:一个儿子只有一个爸爸,一个爸爸可以有很多个儿子

package com.oop.demo05;

//人:父类
public class Person {
    private int money = 10_000_000;

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public void say() {
        System.out.println("说了一句话");
    }
}

package com.oop.demo05;

//Student is Person 子类;派生类
//子类继承了父类,就会拥有父类的全部public方法	private无法被继承
//快捷键 ctrl + h 打开树 最高层有一个object类 Java中所有的类都默认直接或间接继承Object类
public class Student extends Person{
}

package com.oop.demo05;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
        student.setMoney(100);
        System.out.println(student.getMoney());
    }
}

Super详解

package com.oop.demo05;

//人:父类
public class Person {
    protected String name = "abc";

public void print() {
    System.out.println("Person");
}
//父类构造器 alt+insert


    public Person() {
    System.out.println("Person无参构造");
    }
}

package com.oop.demo05;

public class Student extends Person{
private String name  = "def";

public void print() {
    System.out.println("Student");
}

public void test(String name) {
    System.out.println(name);
    //输出传递的name
    System.out.println(this.name);
    //输出def
    System.out.println(super.name);
    //输出abc
    
}
public void test1() {
    print();    //student
    this.print();   //student
    super.print();  //person
}

    public Student() {
    //有一个隐藏代码:super();自动调用父类构造器,且必须在子类构造器第一行
        System.out.println("Student无参构造");
    }
}

package com.oop.demo05;

public class Application {
    public static void main(String[] args) {

        Student student = new Student();
        student.test("myName");
        student.test1();
    }
}

super注意点:

  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super必须只能出现在子类的方法或者构造方法中
  3. super和this不能同时调用构造方法

与this的不同点

代表的对象不同:

this:本身调用这个对象

super:代表父类对象的引用

前提:

this没用继承也能使用

super只能在继承条件才可以使用

构造方法:

this();本类的构造

super();父类的构造

方法的重写

静态static:

package com.oop.demo05;

//重写都是方法的重写,和属性无关
public class B {

    public static void test() {
        System.out.println("B=>test()");
    }
}

package com.oop.demo05;

//继承关系
public class A extends B {
    
    public static void test() {
        System.out.println("A=>test()");
    }
}

package com.oop.demo05;

public class Application {
    public static void main(String[] args) {

        //静态方法的调用只和左边定义的数据类型有关
        A a = new A();
        a.test();   //A类的方法

        //父类的引用指向了子类
        B b = new A();
        b.test();   //B类的方法
    }
}

运行结果为:

B => test()

A => test()

非静态:

package com.oop.demo05;

//重写都是方法的重写,和属性无关
public class B {

    public  void test() {
        System.out.println("B=>test()");
    }
}

package com.oop.demo05;

//继承关系
public class A extends B {
    //override:重写 使用alt+insert 默认调用父类的方法 
    @Override //注解:有功能的注释
    public void test() {
        System.out.println("A=>test()");
    }
}
package com.oop.demo05;

public class Application {
    public static void main(String[] args) {

       
        A a = new A();
        a.test();   //A类的方法

        //父类的引用指向了子类
        B b = new A();	//	//子类重写了父类的方法
        b.test();   
    }
}

运行结果:

A=>test()

A=>test()

方法的重写只与非静态的方法有关,不要加static,由上一讲的图示知道static和类一起加载

重写:需要有继承关系,子类重写父类的方法,方法体不同

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可以扩大但不能缩小 public > protected > default > private
  4. 抛出的异常:范围可以被缩小,但不能扩大

无法重写的情况

  1. static方法,属于类,不属于实例
  2. final 常量
  3. private方法

为什么要重写:

父类的功能子类不一定需要,或者不一定满足

多态

package com.oop.demo06;

public class Person {
    public void run() {
        System.out.println("run");
    }
}

package com.oop.demo06;

public class Student extends Person {
}

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        //new Student(); 就是Student new Person(); 就是Person
        //可以指向的引用类型就不确定

        //同样是student但是有多种引用类型形态 —— 多态
        Student s1 = new Student();
        Person s2 = new Student();  //父类的引用指向子类的类型
        Object s3 = new Student();

        s2.run();
		s1.run();
    }
}

运行结果:

run

run

对Student类run()方法重写

package com.oop.demo06;

public class Student extends Person {
    @Override
    public void run() {
        System.out.println("son runs");
    }
}

运行结果:

son runs

son runs

由上一讲我们知道:子类重写了父类的方法,父类执行子类的方法

给Student类多写一个eat方法

package com.oop.demo06;

public class Student extends Person {
    @Override
    public void run() {
        System.out.println("son runs");
    }
    public void eat() { 
        System.out.println("eat");
    }
}

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        //new Student(); 就是Student new Person(); 就是Person
        //可以指向的引用类型就不确定

        //同样是student但是有多种引用类型形态 —— 多态
        //Student能调用的方法都是自己的或者继承父类的
        Student s1 = new Student();
        //Person 父类 可以指向子类,但是不能调用子类独有的方法
        Person s2 = new Student();  //父类的引用指向子类的类型
        Object s3 = new Student();

        //对象能执行哪些方法,主要看对象左边的类型,和右边的关系不大
        s1.eat();	//能运行eat
        s2.eat();	//报错 s2不能调用子类独有的方法 解决方法:((Student)s2).eat(); 大转小

    }
}

多态注意事项

  1. 多态是方法的多态,属性没有多态
  2. 父类和子类有联系 将狗转换成猫(非父子关系)会出现类型转换问题ClassCastException
  3. 存在条件:继承关系,方法需要重写,父类引用指向子类对象

instanceof和类型转换

instance0f

package com.oop;
//这几个类里面都没装东西
import com.oop.demo06.Person;	
import com.oop.demo06.Student;
import com.oop.demo06.Teacher;

public class Application {
    public static void main(String[] args) {
     Object object = new Student();

        System.out.println(object instanceof Student);  //true
        System.out.println(object instanceof Person);   //true
        System.out.println(object instanceof Object);   //true
        System.out.println(object instanceof Teacher);  //false 不报错是因为object和teacher还有点关系
        System.out.println(object instanceof String);

        System.out.println("====================================================");

        Person person = new Student();

        System.out.println(person instanceof Student);  //true
        System.out.println(person instanceof Person);   //true
        System.out.println(person instanceof Object);   //true
        System.out.println(person instanceof Teacher);  //false 不报错是因为person和teacher还有点关系
       // System.out.println(person instanceof String);   //报错 person和String都是Object下的但是两者没有半毛钱关系直接报错

        System.out.println("=======================================================");

        Student student = new Student();

        System.out.println(student instanceof Student); //true
        System.out.println(student instanceof Person);  //true
        System.out.println(student instanceof Object);  //true
        //System.out.println(student instanceof Teacher);   //编译就报错 同属person下 但是两者互不相干




        //System.out.println(X instanceof Y);
        //能否编译通过就看x的引用类型是否和Y有父子关系
        //true:X的实际new的类型是Y的子类

    }
}

类型转换

package com.oop.demo06;

public class Student extends Person {
public void go() {
    System.out.println("go");
}

}
package com.oop;

import com.oop.demo06.Person;	//空的
import com.oop.demo06.Student;	//有go方法
import com.oop.demo06.Teacher;	//空的

public class Application {
    public static void main(String[] args) {
   //类型的转换:如同基本类型的转换 高 ->低:强制转换 低 ->高:自动转换
       //高            低
       Person a = new Student();

      // a.go(); 报错 父类不能执行子类独有的方法 将a的类型强制转换成Student类型就可以使用
       Student a1 = (Student) a;
       a1.go();

       //也可以一步到位
       ((Student)a).go();

       //子类转换成父类
       Student b = new Student();
       b.go();
       Person c = b; //子类自动转换父类
       //c.go();  丢失子类特有的方法

    }
}

static关键字

package com.oop.demo07;

//static
public class Student {

private static int age; //静态变量
private double score;   //非静态变量

    public void run() {
        //里面可以调用静态方法
    }
    public static void go() {
        //里面不能调用普通方法 因为static和类一起加载,加载的时候run()还没创建出来
    }

    public static void main(String[] args) {
        Student student = new Student();

        System.out.println(Student.age);    //Student.age.sout通过类来直接使用age   静态变量适合这样操作
        System.out.println(student.age);
        System.out.println(student.score);
        //System.out.println(Student.score); 报错缺少static

        //run();    直接调用run()报错 要先new Student(); 然后对象.方法();
       new Student().run();

       Student.go();    //有了static关键字的go()方法调用go很简单
        go();   //甚至可以连Student都不要
        
    }
}

package com.oop.demo07;

public final class Person { //person被final修饰 Student不能继承Person

    //2.
    {
        //匿名代码块 也可以赋初始值 不建议这样写
        System.out.println("匿名代码块");
    }

    //1
    static {
        //静态代码块 用于加载一些初始数据 只执行一次
        System.out.println("静态代码块");
    }

    public Person() {
        System.out.println("构造方法");
    }

    //3.
    public static void main(String[] args) {
        Person person1 = new Person();
        System.out.println(" ============================================ ");
        Person person2 = new Person();

    }
}

//运行结果:
//静态代码块
//匿名代码块
//构造方法
// ============================================
//匿名代码块
//构造方法
package com.oop.demo07;

//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;

public class Test {

    public static void main(String[] args) {
        System.out.println(random());   //使用静态导入包就可以不用在random前加Math.
        System.out.println(PI); //使用静态导入包直接使用PI
    }


}

抽象类

  1. 不能new这个抽象类,只能靠子类去实现他
  2. 抽象类里可以写普通方法
  3. 抽象方法必须写在抽象类中
package com.oop.demo08;

//abstract:抽象类 和之后学习的接口有相似之处    extends单继承   接口可以多继承
public abstract class Action {

    //只写一个doSomething框架希望有人帮我完成这个方法
    //abstract,抽象方法,只有方法名字,没有方法实现
    public abstract void doSomething();

 public void run() {
     System.out.println("run");
 }
}

package com.oop.demo08;

//抽象类的所有方法,继承了他的子类,都必须要重写来实现他的方法 除非他本身也是abstract 这样就要交给他的子子类去实现
public class A extends Action { //提示必须要重写这个方法 alt+insert implement
    @Override
    public void doSomething() {

    }

}

思考

抽象类不能new,那他存在构造器吗?存在

接口

只有规范,无法自己写方法

接口的本质是契约

声明接口的关键字是interface

package com.oop.demo09;

public interface UserService {
    //接口中的所有定义的方法都是抽象的 默认是public abstract
    void add();
    void delete();
    void update();
    void query();

    int age = 99;   //属性默认为常量 public static final
}

package com.oop.demo09;

public interface TimeService {
    void timer();
}

package com.oop.demo09;

//类可以实现接口,类+implements+接口
//实现接口的类 要在这个类中重写接口中的所有方法

//利用接口实现"多继承"
public class UserServiceImpl implements UserService,TimeService {
    @Override
    public void timer() {

    }

    @Override
    public void add() {

    }

    @Override
    public void delete() {

    }

    @Override
    public void update() {

    }

    @Override
    public void query() {

    }
}

接口总结

  1. 约束
  2. 定义一些方法,让不同的人实现
  3. 方法:public abstract
  4. 属性:public static final
  5. 接口不能被实例化,接口中没有构造方法
  6. implements可以实现多个接口
  7. 实现接口必须要重写接口中的方法
posted @ 2025-04-29 23:57  会编程的啊啵  阅读(20)  评论(0)    收藏  举报