【狂神说Java笔记】面向对象

这篇博客详细介绍了面向对象的编程思想,包括面向过程与面向对象的区别、类与对象的关系、封装、继承、多态等核心概念,并探讨了构造器、对象内存分析、内部类以及抽象类和接口等内容,强调了面向对象在解决复杂问题和多人协作中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象 01:什么是面向对象

面向过程和面向对象
面向过程思想

步骤清晰简单,第一步做什么,第二步做什么。。。

面向过程适合处理一些较为简单的问题

Java 方法就是面向过程

面向对象思想

物以类聚,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对每个分类下的细节进行面向过程的思考。

面向对象适合处理复杂的问题,适合处理需要多人协作的问题!

Java 类就是面向对象

对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

面向对象编程

Object-Oriented Programming,简称OOP

面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。

三大特性:封装,继承,多态(不同的人用相同的方法,会得到不同的结果)

对象,是具体的事物。类,是抽象的,是对对象的抽象。

面向对象 04:类与对象的创建

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

动物、植物、手机、电脑、Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体事物应该具备的特点和行为。

对象是抽象概念的具体实例

张三就是人的一个具体是实例,张三家里的旺财就是狗的一个具体实例。

能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。

创建与初始化对象

使用 new 关键字创建对象,会对创建好的对象分配内存空间、进行默认的初始化、对类中构造器的调用。

package opp.ClassObject;

public class App {
    public static void main(String[] args) {
        // 类实例化后会返回一个自己的对象!
        // xiaoming、xiaohong 就是一个 Student 类的具体实例!

        Student xiaoming = new Student();
        Student xiaohong = new Student();

        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);
        xiaoming.study();

        xiaohong.name = "小红";
        xiaohong.age = 18;
        System.out.println(xiaohong.name);
        System.out.println(xiaohong.age);
        xiaohong.study();
    }
}
package opp.ClassObject;

public class Student {
    // 属性
    String name;
    int age;

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

面向对象 05:构造器详解

package opp.Constructor;

public class App {
    public static void main(String[] args) {
        Person person = new Person("lb", 23);
        System.out.println(person.name);
        System.out.println(person.age);
    }
}

package opp.Constructor;

public class Person {

    String name;
    int age;

    /*
    构造器:
        1. 构造器名必须与类名相同;
        2. 没有返回值
    快捷键:
        按 Alt + Insert 快速生成构造函数
    */

    // 一个类即使什么都不写,它也会存在一个无参构造方法
    // 无参构造的显式定义如下,默认如此,可不写
    public Person() {
    }

    // 有参构造,写了有参构造,默认的无参构造会失效,要调用无参构造,必须手动写上无参构造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

面向对象 06:创建对象内存分析

package opp.NewAnalysis;

public class App {
    public static void main(String[] args) {
        Pet dog = new Pet();

        dog.name = "旺财";
        dog.age = 3;

        System.out.println(dog.name);
        System.out.println(dog.age);
        dog.shout();

        Pet cat = new Pet();
    }
}

package opp.NewAnalysis;

public class Pet {
    String name;
    int age;

    public void shout(){
        System.out.println(this.name + "叫了一声");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VRY8DtNz-1665731711424)(JAVA全栈.assets/image-20220915103654286.png)]

面向对象08:封装详解

封装
该露的露,该藏的藏

程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用。

封装(数据的隐藏)

通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。

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

public class App {
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();

        s1.setId(1);
        s1.setName("lb");
        s1.setGender('男');
        s1.setAge(18);
        s2.setAge(101);

        System.out.println(s1.getId());
        System.out.println(s1.getName());
        System.out.println(s1.getGender());
        System.out.println(s1.getAge());
        System.out.println(s2.getAge());
    }
}

package opp.PackageAnalysis;

public class Student {
    // 属性私有
    private String name;    // 名字
    private int id;         // 学号
    private int age;        // 年龄
    private char gender;    // 性别

    // 提供一些可以操作这些属性的public的get和set方法
    // get 获得数据
    public String getName(){
        return this.name;
    }
    // set 给属性设置值
    public void setName(String name){
        this.name = name;
    }

    // 可按alt + insert后,点Getter和Setter快速生成
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public int getAge() {
        if(age == 0){
            return -1;      // 年龄输入错误,返回 -1
        }else{
            return age;
        }

    }

    public void setAge(int age) {
        if(age > 0 && age < 100){
            this.age = age;
        }
    }
}

面向对象 09:什么是继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。

继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字 extends (“扩展”)来表示。

Java 中类只有单继承,没有多继承。即一个子类只能有一个父类,但一个父类可以有多个子类。

类与类之间的关系除了继承之外,还有依赖、组合、聚合等。

package opp.person;

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

        System.out.println(student.getMoney());
        student.say();

    }
}

package opp.person;

// 父类
// Ctrl + H 打开继承树
// 在 Java 中,所有的类都直接或间接继承 Object 类
public class Person {
    private int money = 100;
    public void say(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }
}

package opp.person;

// 子类继承了父类,就会拥有父类的全部非 private 属性和非 private 方法
public class Student extends Person{

}

package opp.person;

public class Teacher extends Person{

}

面向对象 10:Super详解

package opp.Super;

public class Application {

    public static void main(String[] args){

        Student student = new Student();

        System.out.println("=======testVariable========");
        student.testVariable("lb");
        
        System.out.println("=======testFunction========");
        student.testFunction();
    }
}

package opp.Super;

public class Student extends Person{

    public Student(){
        // 首行隐藏了代码 super(); 调用了父类的无参构造
        super();      // 该语句必须在子类无参构造器的第一行
        //this();     // super() 和 this() 不能同时调用构造方法,都只能在第一行
        System.out.println("Student无参构造执行了");
    }
    private String name = "qinjiang";

    public void print(){
        System.out.println("Student");
    }
    public void testVariable(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }

    public void testFunction(){
        print();
        this.print();
        super.print();
    }
}

package opp.Super;

public class Person {

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

    protected String name = "kuangshen";

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

面向对象 11:方法重写

package opp.MethodOverride.HaveStatic;

// 子类和父类的方法有 static
public class App {
    public static void main(String[] args){
        // 有 static,方法的调用只和左边定义的数据类型有关
        A a = new A();
        a.test();

//        A a1 = new B();           // 会报错
//        a1.test();

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

        B b1 = new B();
        b1.test();

    }
}

package opp.MethodOverride.HaveStatic;

public class A extends B{

    public static void test(){
        System.out.println("A->test");
    }
}

package opp.MethodOverride.HaveStatic;

public class B {

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

package opp.MethodOverride.NoStatic;

// 子类和父类的方法无 static
public class App {
    public static void main(String[] args){
        // 无 static,方法的调用只和右边 new 的有关
        A a = new A();
        a.test();

//        A a1 = new B();           // 会报错
//        a1.test();

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

        B b1 = new B();
        b1.test();

    }
}

package opp.MethodOverride.NoStatic;

public class A extends B {

    // ctrl + o 重写方法
    @Override   // 注解:有功能的注释
    public void test() {
        System.out.println("A->test");
    }
}

package opp.MethodOverride.NoStatic;

public class B {

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

重写

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

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

为什么需要重写?

父类的功能子类不一定需要;父类的功能不够完善,不能满足子类的需要。

面向对象 12:什么是多态

package opp.polymorphism;

public class App {
    public static void main(String[] args){
        // 一个对象的实际类型是确定的
        // new Student();
        // new Person();

        // 可以指向的引用类型就不确定了:父类的引用指向子类
        Student s1 = new Student();
        Person s2 = new Student();
        Object s3 = new Student();

        s2.run();       // 子类重写了父类的方法,执行子类的方法
        // s2.eat();    // 会报错。父类型可以指向子类,但是不能调用子类独有的方法
        s1.eat();
    }
}

package opp.polymorphism;

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

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

    public void eat(){
        System.out.println("eat");
    }
}
多态

即同一方法可以根据发送对象的不同而采用多种不同的行为方式。

一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多。

多态注意事项

父类和子类必须有联系,不然会出现类型转换异常(ClassCastException)。

多态的存在条件
  1. 需要有继承关系
  2. 方法需要被重写
  3. 父类引用指向子类对象

方法的修饰符是以下三种的无法被重写:

  • static 属于类,不属于实例

  • final 常量

  • private

面向对象 13:instanceof 和类型转换

package opp.type;

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

        Object object = new Student();

        // Object > Person > Student
        System.out.println(object instanceof Student);
        System.out.println(object instanceof Person);
        System.out.println(object instanceof Object);
        // Object > Person > Teacher 没 new Teacher();  所以为false
        System.out.println(object instanceof Teacher);
        // Object > String
        System.out.println(object instanceof String);

        System.out.println("================================");
        Person person = new Student();
        // Person > Student
        System.out.println(person instanceof Student);
        System.out.println(person instanceof Person);
        System.out.println(person instanceof Object);
        // Person > Teacher 没 new Teacher();  所以为false
        System.out.println(person instanceof Teacher);
        //System.out.println(person instanceof String);     // 不存在继承关系,编译报错

        System.out.println("================================");
        Student student = new Student();
        System.out.println(student instanceof Student);
        System.out.println(student instanceof Person);
        System.out.println(student instanceof Object);
        //System.out.println(student instanceof Teacher);    // 不存在继承关系,编译报错
        //System.out.println(student instanceof String);     // 不存在继承关系,编译报错

        student.go();
        // 父类的引用可以指向子类的对象,反之不成立
        Person person1 = student;
        ((Student)person).go();     // 父类转换为子类,需要进行强制转换

    }
}

package opp.type;

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

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

public class Teacher extends Person{
}

面向对象14:static关键字详解

package opp.StaticAnalysis;

public class Student {
    private static int age; // 静态的变量
    private double score;   // 非静态的变量

    public void run(){
        System.out.println("run() 调用 go()");
        go();               // go() 是 static 的,先加载,可以被调用
    }

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

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

        System.out.println(Student.age);
        //System.out.println(Student.score);    // 会报错,score必须为static
        System.out.println(s1.age);
        System.out.println(s1.score);

        go();
        s1.go();
        // run();   // 无法直接调用
        s1.run();
        new Student().run();
    }
}

package opp.StaticAnalysis;

public class Person {

    // 加载顺序:静态代码块 > 匿名代码块 > 构造器

    // 可以用来赋初值
    {
        System.out.println("匿名代码块");
    }

    // 只执行一次
    static{
        System.out.println("静态代码块");
    }

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

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

package opp.staticps;

// 静态导入别的类的方法
import static java.lang.Math.random;
import static java.lang.Math.PI;

public class Test {
    public static void main(String[] args) {
        System.out.println(Math.random());
        System.out.println(random());
        System.out.println(PI);
    }
}

面向对象15:抽象类

package opp.abstractclass;

public class Application {
    public static void main(String[] args) {
        //Action action = new Action();   // 不能new这个抽象类(抽象类无对象),只能靠子类去实现它
    }
}
package opp.abstractclass;

public abstract class Action {
    String name;
    int age;
    // 抽象类存在构造器
    public Action(){
        System.out.println("存在构造器");
    }
    public Action(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 抽象方法,只有方法名,没有方法体
    public abstract void doSomething();

    /*
    抽象类:
        1. 不能new这个抽象类(抽象类无对象),只能靠子类去实现它
        2. 抽象类中可以写普通的方法,而抽象方法必须在抽象类中
    好处:相当于一个模板
     */

}
package opp.abstractclass;

public class A extends Action{
    @Override
    public void doSomething() {

    }
}

面向对象16:接口的定义与实现

普通类:只有具体实现

抽象类:具体实现和规范(抽象方法)都有!

接口:只有规范,自己无法写方法,专业的约束!约束和实现分离:面向接口编程

接口就是规范,定义的是一组规则体现了现实世界中“如果你是…则必须能…”的思想。例:如果你是天使,则必须能飞。

接口的本质是契约,就像法律一样,制定好后大家都遵守。

面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。

package opp.Interface;

public interface UserService {
    // 接口中所有定义的属性默认都是 public static final
    public static final int age = 99;
//    // 接口中所有定义的方法默认都是 public abstract
//    // 接口不能被实例化,也就没有构造方法
//    public abstract void run(){
//
//    }
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
package opp.Interface;

// 类可以实现接口
// 实现接口的类,必须要重写接口的方法
// 利用接口可以实现多继承
public class UserServiceImpl implements UserService, TimeService{
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void timer() {

    }
}
package opp.Interface;

public interface TimeService {
    void timer();
}

面向对象 17:N 种内部类

内部类就是在一个类的内部再定义一个类,比如,A 类中定义了一个 B 类,那么 B 类相对 A 类来说就称为内部类,而 A 类相对 B 类来说就是外部类了。

package opp.InnerClass;

public class Outer {
    private int id = 10;

    public void out(){
        System.out.println("这是外部类的方法");
    }

    // 局部内部类
    public void method(){
        class Local{    // 不能加 public 修饰符

        }
    }
    public class Inner{     // 加上 static 修饰符,变成静态内部类,此时不能获得外部类的私有属性
        public void in(){
            System.out.println("这是内部类的方法");
        }

        // 获得外部类的私有属性
        public void getID(){
            System.out.println(id);
        }
    }
}

// 一个 .java文件 中可以有多个 class ,但是只能有一个 public class
class A{

}
package opp.InnerClass;

public class App {
    public static void main(String[] args){
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();

        outer.out();
        inner.in();
        inner.getID();
    }
}
package opp.InnerClass;

public class Test {
    public static void main(String[] args) {
        // 匿名内部类,没有将实例赋给变量
        new Apple().eat();

        UserService userService = new UserService() {
            @Override
            public void Hello() {

            }
        };
    }
}

class Apple{
    public void eat(){
        System.out.println("1");
    }
}

interface UserService{
    void Hello();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值