zoukankan      html  css  js  c++  java
  • JavaSE_day09_类与对象初识、封装、构造方法

    面向对象思想

    面向对象思想概述:
    • Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。

    面向过程和面向对象的区别

    面向过程:“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想,简称 OP。“面向过程”也可称之为“面向记录”编程思想,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。所以面向过程的编程方式关注点不在“事物”上,而是做这件事分几步,先做什么,后做什么。例如:早晨起来:起床、穿衣、洗漱、上班,只要按照这个步骤来,就能实现“一天”的功能,整个这个过程中关注的是一步一步怎么做,并没有关注“人”这个事物。 

    面向对象:“面向对象”(Object Oriented)是一种以对象为中心的编程思想,简称 OO。随着计算机技术的不断提高,计算机被用于解决越来越复杂的问题。一切事物皆对象,通过面向对象的方式,将现实世界的事物抽象成对象。通过面向对象的方法,更利于用人理解的方式对复杂系统进行分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,可以像搭积木的一样快速开发出一个全新的系统。面向对象将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

    package demo01;
    
    import java.util.Arrays;
    
    /*
    面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节。
    面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做事儿。
     */
    public class Demo01PrintArray {
    
        public static void main(String[] args) {
            int[] array = { 10, 20, 30, 40, 50, 60 };
    
            // 要求打印格式为:[10, 20, 30, 40, 50]
            // 使用面向过程,每一个步骤细节都要亲力亲为。
            System.out.print("[");
            for (int i = 0; i < array.length; i++) {
                if (i == array.length - 1) { // 如果是最后一个元素
                    System.out.println(array[i] + "]");
                } else { // 如果不是最后一个元素
                    System.out.print(array[i] + ", ");
                }
            }
            System.out.println("==============");
    
            // 使用面向对象
            // 找一个JDK给我们提供好的Arrays类,
            // 其中有一个toString方法,直接就能把数组变成想要的格式的字符串
            System.out.println(Arrays.toString(array));
        }
    
    }

    使用面向对象编程思想开发系统,在现代开发中会将面向对象贯穿整个过程,

    一般包括:OOA/OOD/OOP:

    • OOA:面向对象分析(Object-Oriented Analysis)
    • OOD:面向对象设计(Object-Oriented Design)
    • OOP:面向对象编程(Object-Oriented Programming)

    面向过程和面向对象有什么关系呢?

    • 面向过程其实是最为实际的一种思考方式,就算是面向对象的方法也是含有面向过程的思想。可以说面向过程是一种基础的方法。它考虑的是实际地实现。一般的面向过程是从上往下步步求精。面向对象主要是把事物给对象化,对象包括属性与行为。当程序规模不是很大时,面向过程的方法还会体现出一种优势。因为程序的流程很清楚,按着模块与函数的方法可以很好的组织。但对于复杂而庞大的系统来说,面向过程显得就很无力了。

    面向对象分析方法分析问题的思路和步骤:

    • 根据问题需要,选择问题所针对的现实世界中的实体。
    • 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
    • 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序 语言,把类构造成计算机能够识别和处理的数据结构。
    • 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。

    面向对象的三大特征

    • 封装 (Encapsulation)
    • 继承 (Inheritance)
    • 多态 (Polymorphism)

    类和对象的概念

    软件存在的意义就是为了解决现实世界当中的问题,它必然模拟现实世界,也就是说现实世界中有什么,软件中就对应有什么。面向对象编程思想中关注点是“对象”或者“事物”,那么在编程语言当中要想创建对象则必须先有类,那么类和对象分别是什么,它们的区别和联系是什么呢?

    面向对象的思想概述

    • 类(Class)和对象(Object)是面向对象的核心概念。
    • 类是对一类事物的描述,是抽象的、概念上的定义
    • 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
    • “万事万物皆对象”

    什么是类

    类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。类是现实世界当中具有共同特征的事物进行抽象形成的模板或概念。而对象是实际存在的个体。例如:“汽车”就是一个类(所有的汽车都有方向盘、发动机、都能形式,这是它们的共同特征),“你家的那个汽车”就是一个真实存在的对象。通过类可以创建对象,对象又被称为实例(instance),这个过程也可以称为实例化。对象1、2、3 具有共同特征,进行抽象形成了类,所以从对象到类称为抽象。

    可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人

    • 面向对象程序设计的重点是类的设计
    • 类的设计,其实就是类的成员的设计
    • 现实中的属性:对应类中的成员变量
    • 现实中的行为:对应类中的成员方法

                       

                            

    类的语法格式

                              

    创建Java自定义类

    步骤:

    1. 定义类(考虑修饰符、类名)
    2. 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
    3. 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
    package demo01;
    
    /*
    定义一个类,用来模拟“学生”事物。其中就有两个组成部分:
    
    属性(是什么):
        姓名
        年龄
    行为(能做什么):
        吃饭
        睡觉
        学习
    
    对应到Java的类当中:
    
    成员变量(属性):
        String name; // 姓名
        int age; // 年龄
    成员方法(行为):
        public void eat() {} // 吃饭
        public void sleep() {} // 睡觉
        public void study() {} // 学习
    
    注意事项:
    1. 成员变量是直接定义在类当中的,在方法外边。
    2. 成员方法不要写static关键字。
     */
    public class Student {
    
        // 成员变量
        String name; // 姓名
        int age; // 姓名
    
        // 成员方法
        public void eat() {
            System.out.println("吃饭饭!");
        }
    
        public void sleep() {
            System.out.println("睡觉觉!");
        }
    
        public void study() {
            System.out.println("学习!");
        }
    
    }

    类的访问机制:

    • 在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。 (例外:static方法访问非static,编译不通过。)
    • 在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中 定义的成员

    类的使用格式(对象的创建和使用) 

                                         

    什么是对象

    对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。

    • 对象的属性以变量形式存在,并且这里所说的变量是成员变量当中的实例变量。实例变量就是对象级别的变量,这样的变量要求必须先存在对象,通过对象才能访问。例如:“中国人”这个类,有一个属性是“身份证号”,每一个中国人的“身份证号”都是不一样的,所以身份证号必须使用一个真实存在的“中国人对象”来访问。不能使用“中国人”这个类去访问身份证号。一个类可以实例化 N 多个对象,假设通过“中国人”这个类创建了 100 个“中国人对象”,那么“身份证号”必然会有 100 个实例变量空间去存储。
    • 对象的行为以方法形式表示,并且这里所说的方法是成员方法。对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。成员方法多个对象共用的一份。当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。

    类与对象的关系

    • 类是对一类事物的描述,是抽象的。
    • 对象是一类事物的实例,是具体的。
    • 类是对象的模板,对象是类的实体。

    通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。

    1.导包:也就是指出需要使用的类,在什么位置。

    • 格式:import 包名称.类名称;

    对于和当前类属于同一个包的情况,可以省略导包语句不写。

    2. 创建对象

    • 格式:类名称 对象名 = new 类名称();

    3. 使用,分为两种情况:(也就是,想用谁,就用对象名点儿谁)

    • 使用成员变量:对象名.成员变量名
    • 使用成员方法:对象名.成员方法名(参数)

    注意事项:

    • 如果成员变量没有进行赋值,那么将会有一个默认值,规则和数组一样。

    我们现在创建对象使用上面定义的类

    package demo01;
    
    /*
    注意事项:
    如果成员变量没有进行赋值,那么将会有一个默认值,规则和数组一样。
     */
    public class Demo02Student {
    
        public static void main(String[] args) {
            // 1. 导包。
            // 我需要使用的Student类,和我自己Demo02Student位于同一个包下,所以省略导包语句不写
    
            // 2. 创建,格式:
            // 类名称 对象名 = new 类名称();
            // 根据Student类,创建了一个名为stu的对象
            Student stu = new Student();
    
            // 3. 使用其中的成员变量,格式:
            // 对象名.成员变量名
            System.out.println(stu.name); // null
            System.out.println(stu.age); // 0
            System.out.println("=============");
    
            // 改变对象当中的成员变量数值内容
            // 将右侧的字符串,赋值交给stu对象当中的name成员变量
            stu.name = "赵丽颖";
            stu.age = 18;
            System.out.println(stu.name); // 赵丽颖
            System.out.println(stu.age); // 18
            System.out.println("=============");
    
            // 4. 使用对象的成员方法,格式:
            // 对象名.成员方法名()
            stu.eat();
            stu.sleep();
            stu.study();
        }
    
    }

    注意事项:

    • 如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。
    • 对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。成员方法多个对象共用的一份
    • 当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。 

    面向对象在理解

    /*
     * 一、设计类,其实就是设计类的成员
     * 
     *  属性 = 成员变量 = field = 域、字段
     *  方法 = 成员方法 = 函数 = method
     * 
     *  创建类的对象 = 类的实例化 = 实例化类
     * 
     * 二、类和对象的使用(面向对象思想落地的实现):
     *  1.创建类,设计类的成员
     *  2.创建类的对象
     *  3.通过“对象.属性”或“对象.方法”调用对象的结构
     *  
     * 三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
     *   意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
     *   
     * 四、对象的内存解析
     */
    //测试类
    public class PersonTest {
        public static void main(String[] args) {
            //2. 创建Person类的对象
            Person p1 = new Person();
            //Scanner scanner = new Scanner(System.in);
            
            //调用对象的结构:属性、方法
            //调用属性:“对象.属性”
            p1.name = "Tom";
            p1.isMale = true;
            System.out.println(p1.name);
            
            //调用方法:“对象.方法”
            p1.eat();
            p1.sleep();
            p1.talk("Chinese");
            
            //*******************************
            Person p2 = new Person();
            System.out.println(p2.name);//null
            System.out.println(p2.isMale);
            //*******************************
            //将p1变量保存的对象地址值赋给p3,导致p1和p3指向了堆空间中的同一个对象实体。
            Person p3 = p1;
            System.out.println(p3.name);//Tom
            
            p3.age = 10;
            System.out.println(p1.age);//10
            
        }
    }
    
    //1.创建类,设计类的成员
    class Person{
        
        //属性
        String name;
        int age = 1;
        boolean isMale;
        
        //方法
        public void eat(){
            System.out.println("人可以吃饭");
        }
        
        public void sleep(){
            System.out.println("人可以睡觉");
        }
        
        public void talk(String language){
            System.out.println("人可以说话,使用的是:" + language);
        }
        
    }

    对象的内存解析

    为了更好的理解上面的程序,先来看看java 虚拟机是如何管理它的内存的,请看下图: 

    程序计数器:

    • 概念:可以看做当前线程所执行的字节码的行号指示器。
    • 特点:线程私有的内存

    java 虚拟机栈(重点):

    • 概念:描述的是 java 方法执行的内存模型。(每个方法在执行的时候会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直至完成的过程,就对应一个栈帧从入栈到出栈的过程。)
    • 特 点 : 线 程 私 有, 生 命 周期 和 线 程 相同 。 这 个 区域 会 出 现 两种 异 常 :StackOverflowError 异常: 若线 程请求 的深 度大于 虚拟 机所允 许的 深度 。OutOfMemoryError 异常:若虚拟机可以动态扩展,如果扩展是无法申请到足够的内存。

    本地方法栈:

    • 概念:它与虚拟机栈所发挥的作用是相似的,区别是 java 虚拟机栈为执行 java 方法服务,而本地方法栈是为本地方法服务。
    • 特点:线程私有,也会抛出两类异常:StackOverflowError 和 OutOfMemoryError。

    java 堆(重点):

    • 概念:是被所有线程共享的一块区域,在虚拟机启动时创建。
    • 特点:线程共享,存放的是对象实例(所有的对象实例和数组),GC 管理的主要区域。可以处于物理上不连续的内存空间。

    方法区(重点):

    • 概念:存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代码等数据。
    • 特点:线程共享的区域,抛出异常 OutOfMemory 异常:当方法区无法满足内存分配需求的时候。

    以上所描述内容,有看得懂的,也有看不懂的,例如:线程、本地方法等,这个需要大家在学习后面内容之后,返回来再看一看,那个时候你就全部明白了。针对于目前来说,大家必须要知道 java 虚拟机有三块主要的内存空间,分别是“虚拟机栈(后面简称栈)”、“方法区”、“堆区”,方法区存储类的信息,栈中存储方法执行时的栈帧以及局部变量,堆区中主要存储 new 出来的对象,以及对象内部的实例变量。其中垃圾回收器主要针对的是堆内存,方法区中最先有数据,因为程序执行之前会先进行类加载。栈内存活动最频繁,因为方法不断的执行并结束,不断的进行压栈弹栈操作。将目前阶段需要掌握的内存空间使用一张简单的图表示出来,这个图是大家需要掌握的:

                 

    大概了解了 java 虚拟机内存分配之后,来看看以下代码在执行过程中

    一个对象,调用一个方法内存图 、

    两个对象,调用同一方法内存图

    使用对象类型,作为参数传递到方法中内存图 

    同理:使用对象类型,作为方法的返回值返回的是对象的内存地址值

    成员变量与局部变量区别

    变量根据定义位置的不同,我们给变量起了不同的名字。

    • 在方法体外,类体内声明的变量称为成员变量
    • 在方法体内部声明的变量称为局部变量。
    package demo03;
    
    /*
    局部变量和成员变量
    
    1. 定义的位置不一样【重点】
    局部变量:在方法的内部
    成员变量:在方法的外部,直接写在类当中
    
    2. 作用范围不一样【重点】
    局部变量:只有方法当中才可以使用,出了方法就不能再用
    成员变量:整个类全都可以通用。
    
    3. 默认值不一样【重点】
    局部变量:没有默认值,如果要想使用,必须手动进行赋值
    成员变量:如果没有赋值,会有默认值,规则和数组一样
    
    4. 内存的位置不一样(了解)
    局部变量:位于栈内存
    成员变量:位于堆内存
    
    5. 生命周期不一样(了解)
    局部变量:随着方法进栈而诞生,随着方法出栈而消失
    成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失
     */
    public class Demo01VariableDifference {
    
        String name; // 成员变量
    
        public void methodA() {
            int num = 20; // 局部变量
            System.out.println(num);
            System.out.println(name);
        }
    
        public void methodB(int param) { // 方法的参数就是局部变量
            // 参数在方法调用的时候,必然会被赋值的。
            System.out.println(param);
    
            int age; // 局部变量
    //        System.out.println(age); // 没赋值不能用
    
    //        System.out.println(num); // 错误写法!
            System.out.println(name);
        }
    
    }

                                

    如下图所示:

                               

    在类中的位置不同 
    • 成员变量:类中,方法外
    • 局部变量:方法中或者方法声明上(形式参数)
    作用范围不一样 
    • 成员变量:类中
    • 局部变量:方法中
    初始化值的不同 
    • 成员变量:有默认值
    • 局部变量:没有默认值。必须先定义,赋值,最后使用
    在内存中的位置不同 
    • 成员变量:堆内存
    • 局部变量:栈内存
    生命周期不同 
    • 成员变量:随着对象的创建而存在,随着对象的消失而消失
    • 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失 

     

    封装

    为什么需要封装?封装的作用和含义?

    我们程序设计追求“高内聚,低耦合”。

    • 高内聚类的内部数据操作细节自己完成,不允许外部干涉;
    • 低耦合仅对外暴露少量的方法用于使用。

    隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露 的暴露出来。这就是封装性的设计思想。

    原则

    • 将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。

    封装表现:

    • 方法就是一个最基本封装体。
    • 类其实也是一个封装体。

    封装的基本步骤

    1. 使用 private 关键字来修饰成员变量。
    2. 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。

    Java中通过将数据声明为私有的(private),再提供公共的(public) 方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:

    • 隐藏一个类中不需要对外提供的实现细节;
    • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑, 限制对属性的不合理操作;
    • 便于修改,增强代码的可维护性;

    代码示例

    /*
     * 面向对象的特征一:封装与隐藏     3W:what? why? how?
     * 一、问题的引入:
     *  当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到
     *  属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值
     *  加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs())
     *  同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private).
     *  -->此时,针对于属性就体现了封装性。
     *
     * 二、封装性的体现:
     * 我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
     *
     *  拓展:封装性的体现:① 如上  ② 不对外暴露的私有的方法  ③ 单例模式   ...
     *
     *
     * 三、封装性的体现,需要权限修饰符来配合。
     * 1.Java规定的4种权限(从小到大排列):private、缺省、protected 、public
     * 2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
     * 3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
     *        修饰类的话,只能使用:缺省、public
     *
     * 总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。
     *  描述现实生活中的人的事物
     *    属性:  姓名 年龄
     *    功能:  说话
     *
     *  出现安全问题: age问题,可能出现赋值为负数的情况
     *  负数不会导致程序问题,违反生活中的真实情况
     *
     *  提高安全问题: 让外面的类,不允许直接调用我的成员变量
     *  新的关键字  private 私有   属于成员修饰符,不能修饰局部变量
     *  被private修饰的成员,只能在自己的本类中被使用
     *
     *  对私有变量,提供公共的访问方式: 方法
     */
    public class Person {
        //人的姓名,成员变量
        String name;
        //人的年龄,成员变量
        private int age ;
    
        //变量age被私有,提供方法,让外面的类使用
        //定义方法,对age变量进行赋值,方法名字,必须set开头
        public void setAge(int a){
            //对变量参数a进行范围的限制
            if(a<0 || a > 200){
                //如果a超过范围,手动将age赋值为20
                age = 20;
            }else{
                //如果a没有超过范围,直接对age赋值
                age = a;
            }
        }
    
        //定义方法,对变量age获取值使用,方法名字get
        public int getAge(){
            return age;
        }
    
    
        //定义人的说话功能,方法中,要求说出自己的姓名和年龄
        public void speak(){
            System.out.println(name+"..."+age);
        }
    }

    测试类

    package demo04;
     
     
    /*
     *   定义好的Person类进行测试
     *   创建对象,对象调用属性和方法
     */
    public class PersonTest {
     
        public static void main(String[] args) {
            //创建Person类的对象  new
            Person p = new Person();
            //对成员变量赋值
            //p.age = -200;
            //对成员变量age赋值,只能调用Set方法赋值
            p.setAge(50);
     
            p.name = "张三";
            //调用类中方法
            p.speak();
     
            //输出成员变量age值,必须调用get方法
            System.out.println(p.getAge());
        }
     
    }

    四种访问权限修饰符

            

    可见,public具有最大权限。private则是最小权限。被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作

    • 提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰
    • 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰

    编写代码时,如果没有特殊的考虑,建议这样使用权限:

    • 成员变量使用 private ,隐藏细节。
    • 构造方法使用 public ,方便创建对象。
    • 成员方法使用 public ,方便调用方法。

    小贴士:不加权限修饰符,其访问能力与default修饰符相同

    封装优化之this关键字

    • this 可以看做一个变量,它是一个引用,存储在 Java 虚拟机堆内存的对象内部,this 这个引用保存了当前对象的内存地址指向自身,任何一个堆内存的 java 对象都有一个 this,也就是说创建 100 个 java 对象则分别对应 100 个 this。
    • this 指向“当前对象”,也可以说 this 代表“当前对象,this 可以使用在实例方法中以及构造方法中,语法格式分别为“this.”和“this(..)”。
    • this不能出现在 static的方法当中,这是为什么呢?首先static 的方法,在调用的时候是不需要创建对象的,直接采用“类名”的方式调用,也就是说static 方法执行的过程中是不需要“当前对象”参与的,所以 static 的方法中不能使用 this,因为 this 代表的就是“当前对象”。

    代码举例

    /*
     * this关键字的使用:
     * 1.this可以用来修饰、调用:属性、方法、构造器
     * 
     * 2.this修饰属性和方法:
     *   this理解为:当前对象  或 当前正在创建的对象
     * 
     *  2.1  在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,
     *   通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式
     *   的使用"this.变量"的方式,表明此变量是属性,而非形参。
     * 
     *  2.2 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。
     *  但是,通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式
     *   的使用"this.变量"的方式,表明此变量是属性,而非形参。
     * 
     * 3. this调用构造器
     *       ① 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
     *    ② 构造器中不能通过"this(形参列表)"方式调用自己
     *    ③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)"
     *    ④ 规定:"this(形参列表)"必须声明在当前构造器的首行
     *    ⑤ 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
     * 
     * 
     
        this:
            1、this是一个关键字,全部小写。
            2、this是什么,在内存方面是怎样的?
                一个对象一个this。
                this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。
                所以,严格意义上来说,this代表的就是“当前对象”
                this存储在堆内存当中对象的内部。
    
            3、this只能使用在实例方法中。谁调用这个实例方法,this就是谁。
            所以this代表的是:当前对象。
    
            4、“this.”大部分情况下是可以省略的。
    
            5、为什么this不能使用在静态方法中??????
                this代表当前对象,静态方法中不存在当前对象。
    */
    public class ThisDemo {
        public static void main(String[] args) {
    
            Customer c1 = new Customer("张三");
            c1.shopping();
    
            Customer c2 = new Customer("李四");
            c2.shopping();
    
            Customer.doSome();
        }
    }
    
    // 顾客类
    class Customer {
    
        // 属性
        // 实例变量(必须采用“引用.”的方式访问)
        String name;
    
        //构造方法
        public Customer() {
    
        }
    
        public Customer(String s) {
            name = s;
        }
    
        // 顾客购物的方法
        // 实例方法
        public void shopping() {
            // 这里的this是谁?this是当前对象。
            // c1调用shopping(),this是c1
            // c2调用shopping(),this是c2
            //System.out.println(this.name + "正在购物!");
    
            // this. 是可以省略的。
            // this. 省略的话,还是默认访问“当前对象”的name。
            System.out.println(name + "正在购物!");
        }
    
        // 静态方法
        public static void doSome() {
            // this代表的是当前对象,而静态方法的调用不需要对象。矛盾了。
            // 错误: 无法从静态上下文中引用非静态 变量 this
            //System.out.println(this);
        }
    }
    
    
    class Student {
    
        // 实例变量,怎么访问?必须先new对象,通过“引用.”来访问。
        String name = "zhangsan";
    
        // 静态方法
        public static void m1() {
            //System.out.println(name);
    
            // this代表的是当前对象。
            //System.out.println(this.name);
    
            // 除非你这样
            Student s = new Student();
            System.out.println(s.name);
    
        }
    
        //为什么set和get方法是实例方法?
        public void setName(String s) {
            name = s;
        }
    
        public String getName() {
            return name;
        }
    
        // 什么时候方法定义为实例方法,什么时候定义为静态方法?
        // 如果方法中直接访问了实例变量,该方法必须是实例方法。
    }

    在实例方法中,或者构造方法中,为了区分局部变量和实例变量,这种情况下:this. 是不能省略的。

    /*
    1、this可以使用在实例方法中,不能使用在静态方法中。
    2、this关键字大部分情况下可以省略,什么时候不能省略呢?
        在实例方法中,或者构造方法中,为了区分局部变量和实例变量,
        这种情况下:this. 是不能省略的。
    */
    public class ThisTest03{
        public static void main(String[] args){
    
            Student s = new Student();
            s.setNo(111);
            s.setName("张三");
            System.out.println("学号:" + s.getNo());
            System.out.println("姓名:" + s.getName());
    
            Student s2 = new Student(2222, "李四");
            System.out.println("学号:" + s2.getNo());
            System.out.println("姓名:" + s2.getName());
    
        }
    }
    
    // 学生类
    class Student{
        //学号
        private int no;
    
        //姓名
        private String name;
    
        //构造方法无参
        public Student(){
        
        }
    
    
        // 上面的有参构造方法也增强以下可读性
        public Student(int no, String name){
            this.no = no;
            this.name = name;
        }
    
    
        public void setNo(int no){ 
            //no是局部变量
            //this.no 是指的实例变量。
            this.no = no; // this. 的作用是:区分局部变量和实例变量。
        }
        public int getNo(){
            return no;
            //return this.no;
        }
        
        public void setName(String name){
            this.name = name;
        }
    
    
    
        public String getName(){ // getName实际上获取的是“当前对象”的名字。
            //return this.name; // 严格来说,这里是有一个 this. 的。只不过这个 this. 是可以省略的。
            return name;
        }
    }

    this 还有另外一种用法,使用在构造方法第一行(只能出现在第一行,这是规定,记住就行),通过当前构造方法调用本类当中其它的构造方法,其目的是为了代码复用。调用时的语法格式是:this(实际参数列表)

    /*
        1、this除了可以使用在实例方法中,还可以用在构造方法中。
        2、新语法:通过当前的构造方法去调用另一个本类的构造方法,可以使用以下语法格式:
            this(实际参数列表);
                通过一个构造方法1去调用构造方法2,可以做到代码复用。
                但需要注意的是:“构造方法1”和“构造方法2” 都是在同一个类当中。
    
        3、this() 这个语法作用是什么?
            代码复用。
        
        4、死记硬背:
            对于this()的调用只能出现在构造方法的第一行。
    */
    public class ThisTest04{
        public static void main(String[] args){
            // 调用无参数构造方法
            Date d1 = new Date();
            d1.detail();
    
            // 调用有参数构造方法
            Date d2 = new Date(2008, 8, 8);
            d2.detail();
        }
    }
    
    /*
    需求:
        1、定义一个日期类,可以表示年月日信息。
        2、需求中要求:
            如果调用无参数构造方法,默认创建的日期为:1970年1月1日。
            当然,除了调用无参数构造方法之外,也可以调用有参数的构造方法来创建日期对象。
    */
    class Date{ // 以后写代码都要封装,属性私有化,对外提供setter and getter
        //
        private int year;
        //
        private int month;
        //
        private int day;
    
        // 构造方法无参
        // 调用无参数构造方法,初始化的日期是固定值。
        public Date(){
            //错误: 对this的调用必须是构造器中的第一个语句
            //System.out.println(11);
            this(1970, 1, 1);
        }
        // 构造方法有参数
        public Date(int year, int month, int day){
            this.year = year;
            this.month = month;
            this.day = day;
        }
    
        // 提供一个可以打印日期的方法
        public void detail(){
            //System.out.println(year + "年" + month + "月" + day + "日");
            System.out.println(this.year + "年" + this.month + "月" + this.day + "日");
        }
    
        //setter and getter
        public void setYear(int year){
            // 设立关卡(有时间可以设立关卡)
            this.year = year;
        }
        public int getYear(){
            return year;
        }
        public void setMonth(int month){
            // 设立关卡(有时间可以设立关卡)
            this.month = month;
        }
        public int getMonth(){
            return month;
        }
        public void setDay(int day){
            // 设立关卡(有时间可以设立关卡)
            this.day = day;
        }
        public int getDay(){
            return day;
        }
    }

    总结一下this的用法

    构造器(构造方法)

    • 我们对封装已经有了基本的了解,接下来我们来看一个新的问题,依然以Person为例,由于Person中的属性都被private了,外界无法直接访问属性,必须对外提供相应的set和get方法。当创建人对象的时候,人对象一创建就要明确其姓名和年龄,那该怎么做呢?使用构造方法,那什么是构造方法呢?从字面上理解即为构建创造时用的方法,即就是对象创建时要执行的方法。既然是对象创建时要执行的方法,那么只要在new对象时,知道其执行的构造方法是什么,就可以在执行这个方法的时候给对象进行属性赋值。

    构造方法的作用:

    • 当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。

    注 意:

    • Java语言中,每个类都至少有一个构造器
    • 默认构造器的修饰符与所属类的修饰符一致
    • 一旦显式定义了构造器,则系统不再提供默认构造器
    • 一个类可以创建多个重载的构造器,具体调用哪个构造方法,那要看调用的时候传递的实际参数列表符合哪个构造方法了
    • 父类的构造器不可被子类继承
    • 构造方法名和类名一致。 
    • 构造方法返回值类型不需要写,写上就报错,包括 void 也不能写
    • 无参数构造方法又叫做缺省构造器,或者默认构造方法。
    • 一般在开发中为了方便编程,建议程序员手动的将无参数构造方法写上,因为不写无参数构造方法的时候,这个默认的构造方法很有可能就不存在了,另外也是因为无参数构造方法使用的频率较高。

    代码演示

    /*
     * 类的结构之三:构造器(或构造方法、constructor)的使用
     * construct:建设、建造。  construction:CCB    constructor:建设者
     *
     * 一、构造器的作用:
     * 1.创建对象
     * 2.初始化对象的信息
     *
     * 二、说明:
     * 1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
     * 2.定义构造器的格式:权限修饰符  类名(形参列表){}
     * 3.一个类中定义的多个构造器,彼此构成重载
     * 4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
     * 5.一个类中,至少会有一个构造器。
     */
    public class PersonTest {
        public static void main(String[] args) {
            //创建类的对象:new + 构造器
            Person p = new Person();
    
            p.eat();
    
            Person p1 = new Person("Tom");
    
            System.out.println(p1.name);
    
    
        }
    }
    
    class Person {
        //属性
        String name;
        int age;
    
        //构造器
        public Person() {
            System.out.println("Person().....");
        }
    
        public Person(String n) {
            name = n;
    
        }
    
        public Person(String n, int a) {
            name = n;
            age = a;
        }
    
    
        //方法
        public void eat() {
            System.out.println("人吃饭");
        }
    
        public void study() {
            System.out.println("人可以学习");
        }
    
    }

    构造方法和一般方法区别

    • 构造方法在对象创建时就执行了,而且只执行一次。
    • 一般方法是在对象创建后,需要使用时才被对象调用,并可以被多次调用。

    注意:

    • 可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其他的构造器!
    • 明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
    • 如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了 "this(形参列表)"
    • "this(形参列表)"必须声明在类的构造器的首行!
    • 在类的一个构造器中,最多只能声明一个"this(形参列表)"

    总结:属性赋值过程

    截止到目前,我们讲到了很多位置都可以对类的属性赋值。现总结这几个位 置,并指明赋值的先后顺序。赋值的位置:

    • ① 默认初始化,实例变量没有手动赋值的时候,实际上系统会默认赋值,实例变量是在构造方法执行的过程中完成初始化的,完成赋值的。
    • ② 显式初始化
    • ③ 构造器中初始化
    • ④ 通过“对象.属性“或“对象.方法”的方式赋值

    赋值的先后顺序: ① - ② - ③ - ④

    标准代码——JavaBean

    JavaBean 是 Java语言编写类的一种标准规范。符合 JavaBean 的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的 set 和 get 方法。

    步骤如下图所示:

    示例:

    /*
        成员变量
            使用private修饰
        构造方法
            提供一个无参构造方法
            提供一个带多个参数的构造方法
        成员方法
            提供每一个成员变量对应的setXxx()/getXxx()
            提供一个显示对象信息的show()
     */
    public class Student {
        //成员变量
        private String name;
        private int age;
     
        //构造方法
        public Student() {
        }
     
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
     
        //成员方法
        public void setName(String name) {
            this.name = name;
        }
     
        public String getName() {
            return name;
        }
     
        public void setAge(int age) {
            this.age = age;
        }
     
        public int getAge() {
            return age;
        }
     
        public void show() {
            System.out.println(name + "," + age);
        }
    }
  • 相关阅读:
    知物由学 | 未来安全隐患:AI的软肋——故意欺骗神经网络
    IT和非IT人士:2分钟了解什么是区块链
    追踪掠食者:地下灰产如何撸死创业公司?
    机器学习、深度学习、和AI算法可以在网络安全中做什么?
    一文了解安卓APP逆向分析与保护机制
    如何做好iOS应用安全?这有一把行之有效的“三板斧”
    微服务化不同阶段 Kubernetes 的不同玩法
    从B站、爱奇艺、映客的IPO上市,看国内视频公司的内容审核现状
    知物由学 | 你的网络安全问题背后的真正原因
    感动到流泪!数据分析师的福音:跨视图粒度计算
  • 原文地址:https://www.cnblogs.com/wurengen/p/13458293.html
Copyright © 2011-2022 走看看