美文网首页Java
[Java]重学Java-初学面向对象与对象初始化

[Java]重学Java-初学面向对象与对象初始化

作者: AbstractCulture | 来源:发表于2021-04-11 01:22 被阅读0次

    面向对象是什么?

    在前面的章节中,我们设计程序总是趋向于设计过程来解决问题,更加准确的来说,通过"算法+数据结构"来设计程序。如果是求解一个简单的问题,这样做是完全没有问题的。但是现实生活中,人们的需求总是变化莫测,所以需要一种复用性更强的方式来设计程序,这个时候,OOP(Object-oriented programming)则以面向对象方式闪亮登场了。
    OOP其实不是Java语言的专属,在其他语言上,你也可以看到面向对象的影子,例如:C#TypeScriptC++等都是经典的面向对象编程语言。
    在面向对象的世界里面,程序都是一个个对象组成的,通过对象间的消息传递来完成作业。

    对象到底是什么?

    这个一个很大的课题,这里简单讲讲一些基本的概念.

    • 描述一个对象,首先要有一个建模的模板,在Java中,这个模板称为类;对象大多数是对现实生活的抽象,比如与时间相关的操作,在面向对象里面就对应一个类:Date
    • 类是对象的模板,对象是类的实例,这里的关系就像-人都拥有名字和身份证,但是每个人都拥有自己的名字和身份证,那么"人"和"张三"之间的关系就是类与对象的关系.
    • 对象内部封装了数据,对外提供方法进行通信.数据的表现称为状态,方法则是对象的行为,通过行为可以改变对象的状态

    面向对象的三大基本原则

    封装

    封装的概念比较容易理解,先以一个生活的例子作为举例:
    一台电视机,内部可能有很多复杂的设计结构和硬件设备,那么直接让用户去操作这些内部的零件可能会造成很大的困扰,于是厂商就提供了一系列的按钮、遥控器来让用户更好地操作电视机。
    这其实就是一个封装的过程,内部细节对用户屏蔽,用户只需要知道,通过这个"按钮"我可以达成怎样的效果即可。这在程序中的体现则是:调用一个工具类的方法,我需要输入什么,它会给我输出什么.

    继承

    继承是为了更好地扩展与复用,通过继承可以直接得所扩展的类的所有能力(通常称为父类),如此一来可以避免重复性的工作;同时,继承也意味这这组对象拥有部分相同的特征,那么它们的"类型"也是一致的.

    例如,在Java中,你会常常看到这样的写法.

    User person = new Person();
    

    Java只支持单继承.

    多态

    多态的方式可以有很多种不同的呈现:

    • 面对同一个消息,不同的对象会产生不同的不同的行为,这在Java中体现为重写-Override.
    • 相同名字的方法,通过不同的参数进行区分,调用时支持不同的方法匹配相应的方法.这便是重载的体现.

    这里引用《Java编程思想》中的一句话:发送消息给对象时,如果程序不知道接收的具体类型是什么,但最终执行是正确的,这就是对象的“多态性”(Polymorphism)。面向对象的程序设计语言是通过“动态绑定”的方式来实现对象的多态性的。

    类之间的关系

    • uses-a: 类A中的一个方法操纵了另一个类的对象,那么类A的这个功能便依赖了B.程序中应该尽量减少类与类之间的依赖关系,降低类与类之间的耦合度.
    • has-a: 类A中持有类B作为自己的成员,例如一个User类持有了一组角色.这便是聚合关系.
    public class User{
        /**
         * 角色列表
         */
        private List<Role> roles;
    }
    
    • is-a: 继承关系,例如:类A继承自类B.

    什么是Java对象?

    谈起Java中的对象,不得不提起类.要生产一个对象,首先得描述一个模板,就像工厂里面,我们想造一个手机壳,那么我们首先得设计一个模具,再根据这个模具加工出手机壳。
    类与对象之间的关系也是如此:
    类中可以描述一个对象的特征:例如field(成员变量)constructor构造器method方法class-类型.
    程序中可以通过new关键字来触发构造器,进而获取一个对象,通过调用方法,可以改变对象的状态.

    new与构造器

    使用new关键字来生产一个对象,在new的过程中,会自动触发构造器方法.
    其中,对于构造方法的概述为:

    1. 构造器方法与类名一致.
    2. 一个类可以声明多个构造器方法.
    3. 构造器方法支持多态性.
    4. 构造器方法不需要声明返回值.
    5. 搭配修饰符可以控制构造器方法的使用范围.

    口说无凭,我们通过代码进行讲解:

    • 定义一个用户类
    package com.tea.modules.model;
    
    public class User 
        /**
         * 用户名称
         */
        private String userName;
        /**
         * 密码
         */
        private String password;
        /**
         * 这是一个构造器方法
         */
        public User(){
            System.out.println("一个User对象被创建出来了");
        }
    }
    
    • 生产对象
    User user = new User();
    
    • Result
    new

    我们这里验证了一个问题,使用new去生产对象实例的时候,会自动触发构造器方法,这个过程也称为初始化.

    • 如果直接声明对象,那么你仅仅只得到一个指针

    错误示范

    User user;
    System.out.println(user.toString());
    

    无参构造器

    定义Java类的时候,如果你不需要自定义创建对象的过程,你完全可以不写构造器方法,编译器会为你自动创建一个无参的构造器.
    如果显式声明了构造器,那么编译器便不会为你创建构造器了.

    static

    被static修饰的方法代表静态方法,它不归属于对象,而是类.
    在类中定义static初始化方法,往往只会执行一次,因为加载出类(对象的模板)之后,就可以直接根据模板来生产对象了,也就是说,要得到一个User对象,必须先加载出一个User.class.

    static方法无法通过this关键字进行调用,需要使用"类名.方法"的方式进行调用.

    // 静态方法
    Math.pow(1, 2);
    

    new的时候,底层做了什么事情?

    为了更好的了解这个问题,我们将User类的age属性声明为int(当然实际开发中不提倡这样做),这里为了重写toString方法,我使用了lombok进行自动生成.

    • User.class
    package com.tea.modules.model;
    import lombok.Data;
    
    
    @Data
    public class User {
        private String userName;
        private String password;
        private int age;
        
        static {
            System.out.println("我是一个静态方法,我是类加载的时候就会发生的事件");
        }
        
        {
            System.out.println("我是一个初始化时执行的方法,我比构造器的优先级要高");
        }
        
        public User(){
            System.out.println("一个User对象被创建出来了");
        }
    }
    
    • Test
    package com.tea.modules.java8.oop;
    
    import com.tea.modules.model.User;
    
    /**
     * 理解面向对象思想-对象的构造器与初始化
     * @author jaymin
     * @since 2021/4/10 16:15
     */
    public class OOPDemo {
    
        public static void main(String[] args) {
            User user = new User();
            System.out.println(user.toString());
        }
    }
    
    • Result
    result
    • 查看编译后的指令
      为了解决这个问题,可以使用javap -c OOPDemo.class查看JVM编译后的指令集.
    编译后的指令
    • 关于new的大致过程
    1. 我们知道,要生产对象就需要找到类,我们定义的java类最终会编译为一个.class文件,JVM首先要将这个文件加载到内存中,得到一个User.class对象.
    2. 执行被static修饰的代码块.
    3. 执行new关键字的相关操作,为当前对象分配内存空间.
    4. 对对象中的所有字段设置为零值(引用类型置为null,基础类型置为默认值,比如int的默认值为0).
    5. 执行代码块,即在字段定义处的初始化动作.
    6. 执行构造器(constructor)方法.
    7. 你获得了一个对象的引用.
    • 图示
    pic

    深入浅出new关键字

    「JVM」 - 对象初始化

    相关文章

      网友评论

        本文标题:[Java]重学Java-初学面向对象与对象初始化

        本文链接:https://www.haomeiwen.com/subject/fkwokltx.html