当前位置:首页 » 《随便一记》 » 正文

Java学习 -- 面向对象概述与封装性_庸人冲的博客

4 人参与  2021年11月07日 07:03  分类 : 《随便一记》  评论

点击全文阅读


文章目录

  • 面向对象思想
    • 概述
    • 面向过程与面向对象的区别
      • 举例
      • 区别
      • 代码展示
    • 特点
    • 面向对象三条主线
  • 类和对象
    • 什么是类
    • 什么是对象
    • 类与对象的关系
    • 类的定义
      • 事物与类的对比
    • 类的定义格式
    • 对象的使用
      • 使用步骤
      • 代码举例
        • 例一
        • 例二
      • 成员变量默认值
      • 对象内存图
        • `jvm`内存划分图
        • 一个对象的内存图
        • 两个对象引用指向不同对象空间的内存图
        • 两个对象引用指向同一对象空间的内存图
      • 对象在方法中的使用
        • 使用对象类型作为方法的参数
        • 使用对象类型作为方法的返回值
      • 成员变量和局部变量的区别
      • 练习
    • 方法
      • 方法重载
        • 概念
        • 特点
      • 可变形参的方法
        • 格式
        • 使用
      • **方法参数的值传递机制**
        • 练习
          • 练习1
          • 练习2
      • 递归方法
  • 三大特征之封装
    • 封装概述
      • 概述
      • 原则
      • 体现
    • private关键字
      • 使用说明
      • 间接访问
        • Setter方法
        • Getter方法
      • 练习
    • this关键字
        • **谁调用的方法,this就指向谁。**
        • this 调用构造器
    • 构造器
      • 构造器的定义格式
      • 注意事项
    • 标准代码——JavaBean
      • 举例
  • static
    • 修饰属性
      • 使用场景
      • static内存图
    • 修饰方法
      • 使用场景
    • 修饰代码块
      • 静态代码块

面向对象思想

概述

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

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

面向过程:当需要实现一个功能时,每一个具体的步骤都要亲历亲为,详细处理每一个细节。

面向对象:当需要实现一个功能时,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我们做事。

举例

洗衣服:

面向过程:把衣服脱下来–>找一个盆–>放点洗衣粉–>加点水–>浸泡10分钟–>揉一揉–>清洗衣服–>拧干–>晾起来

面向对象:把衣服脱下来–>打开全自动洗衣机–>扔衣服–>按钮–>晾起来

区别

面向过程:强调步骤

面向对象:强调对象,这里的对象就是洗衣机。

代码展示

public class Demo01PrintArray {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        // 要求打印格式为:[1, 2, 3, 4, 5]

        // 面向过程实现
        System.out.print("[");
        for(int i = 0; i < arr.length; i++){
            if(i < arr.length - 1) {
                System.out.print(arr[i] + ", ");
            } else {
                System.out.println(arr[i] + "]");
            }   // 需要关注功能实现的每一个细节
        }

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

        // 面向对象实现
        System.out.println(Arrays.(arr));
        // 不需要关注功能实现的每一个细节,只需要调用具有这个功能的方法即可。
        //Arrays.toString() 
        //JDK提供的Arrays类中的toString() 方法
        //Arrays.toString() 可以将数组转换成字符串格式
    }
}

在这里插入图片描述

特点

面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。面向对象的语言中,包含了三大基本特征,即封装继承多态

面向对象三条主线

  1. 类及类的成员:属性(成员变量)、成员方法、构造器、代码块、内部类。
  2. 面向对象三大特性:封装、继承、多态。
  3. 其它关键字:this, super, abstract, interface, final, package, import…

类和对象

什么是类

:是一组相关属性行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。

现实中,描述一类事物:

属性:就是该事物的状态信息。

行为:就是该事物能够做什么。

举例:小猫。

属性:名字、体重、年龄、颜色。

行为:走、跑、叫。

什么是对象

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

现实中,一类事物的一个实例:一只小猫。

举例:一只小猫。

属性:tom、5kg、2 years、yellow。

行为:溜墙根走、蹦跶的跑、喵喵叫。

类与对象的关系

类是对一类事物的描述,是抽象的。

对象是一类事物的实例,是具体的。

类是对象的模板,对象是类的实体。

在这里插入图片描述

类的定义

事物与类的对比

  1. 现实世界的一类事物:

    属性:事物的状态信息。

    行为:事物能够做什么。

  2. Java中用class描述事物也是如此:

    成员变量:对应事物的属性

    成员方法:对应事物的行为

类的定义格式

public class ClassName {
    //成员变量
    //成员方法
}

定义类:就是定义类的成员,包括成员变量成员方法

成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外,也叫类的属性,field。

成员方法:和以前定义方法几乎是一样的。只不过把static去掉,static的作用在面向对象后面课程中再详细讲解。

/*
定义一个类,用来模拟"学生",其中就有两个组成部分:
1、属性(是什么):
    姓名、年龄、性别、...
2、行为(能做什么):
    吃饭、睡觉、学习、...

对应到java的类当中:
1、成员变量(属性):
    String name;  // 姓名
    int age;      // 年龄
    byte sex;     // 性别 0:女,1:男,2:保密
2、成员方法(行为):
    public void eat() {}    // 吃饭
    public void sleep() {}  // 睡觉
    public void study() {}  // 学习
 */

public class Student {
    // 成员变量
    String name;  // 姓名
    int age;      // 年龄
    byte sex;     // 性别

    // 成员方法
    public void eat(){
        System.out.println("吃!");
    }

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

    public void study() {
        System.out.println("学!");
    }
}

对象的使用

使用步骤

通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用,具体分为以下三个步骤:

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

    如果类同属于一个包中(同一路径下),可以省略导包语句

// 导包语句
// import packageName.className;
import cn.study.day07.demo03.Demo02Student;
  1. 创建
// className objName = new className();
Student stu = new Student();
  1. 使用

使用成员变量

// objName.memberVarName
stu.name = "张三";

使用成员方法

// objName.memberMethName(para,...)  para可以是0或多个
stu.eat();

总结:想用谁,就用对象名点儿谁。

代码举例

例一

public class Demo02Student {

    public static void main(String[] arg){
        // 1. 导包
        // 需要使用的Student类,和当前所在类同属一个包下,可以省略导包语句。

        // 2. 创建
        // className objName = new className();
        Student stu = new Student();
        // 根据Student类创建了一个stu的对象。

        //3. 使用其中的成员变量
        System.out.println(stu.name);   // null
        System.out.println(stu.age);    // 0
        System.out.println(stu.sex);    // '\u0000'
        // Student类中没有给成员变量赋值
        // 默认值与数组的规则相同
        System.out.println("=====================");

        // 改变对象当中的成员变量内容
        stu.name = "张三";
        stu.age = 18;
        stu.sex = '男';
        System.out.println(stu.name);   // 张三
        System.out.println(stu.age);    // 18
        System.out.println(stu.sex);    // 男

        System.out.println("=====================");
        // 使用成员方法
        stu.eat();
        stu.sleep();
        stu.study();
    }
}

例二

/*
定义一个类,用来模拟"手机"事物

属性:品牌、价格、颜色...
行为:通话、短信...

对应到类当中:
成员变量(属性)
    String brand;
    double price;
    String color;
成员方法(行为)
    public void call(String who) {}  // 打电话
    public void sendMessage() {}     // 群发短信
*/
public class Phone {
    //成员变量
    String brand; // 品牌
    double price; // 价格
    String color; // 颜色

    //成员方法
    public void call(String who){
        System.out.println("给" + who + "打电话");
    }
    public void sendMessage() {
        System.out.println("群发短信");
    }
}
public class Demo03PhoneOne {
    public static void main(String[] args) {
        // 根据Phone类,创建一个名为one的对象;
        Phone one = new Phone();
        System.out.println(one.brand);   // null
        System.out.println(one.price);   // 0.0
        System.out.println(one.color);   // null

        System.out.println("===================");
        // 给对象当中的成员重新赋值
        one.brand = "小米";
        one.price = 998.0;
        one.color = "黑色";

        System.out.println(one.brand);   // 小米
        System.out.println(one.price);   // 998.0
        System.out.println(one.color);   // 黑色

        System.out.println("===================");
        one.call("雷军");
        one.sendMessage();
    }
}

成员变量默认值

成员变量如果未赋值,将会有一个默认值,规则如下:

  1. 整数类型,默认为0;
  2. 浮点类型,默认为0.0;
  3. 字符类型,默认为'\u0000'
  4. 布尔类型,默认为false;
  5. 引用类型,默认为null

对象内存图

jvm内存划分图

在这里插入图片描述

一个对象的内存图

在这里插入图片描述

堆中的成员变量是参考方法区.class中成员变量的信息创建的,其中的值就保存在堆(Heap)中。

堆中的成员方法保存的是一个地址值,指向了方法区中的成员方法信息。

进栈也叫压栈,先进栈的在后进栈的下面,后来的压着先来的。

出栈也叫弹栈,当方法执行完毕后会立刻从栈中销毁,main方法执行完毕,则程序结束。

先进后出,后进先出。

两个对象引用指向不同对象空间的内存图

对象名,也叫对象引用

在这里插入图片描述

从上图可以看到,两个对象在创建时,分别在堆区开辟了不同的内存空间,各自保存着本对象的成员变量和成员方法,但是这两块堆区内存空间同时指向了方法区里同一块空间。也就是它们的所具有的属性和功能是完全相同的,不同的是成员变量的值和成员方法调用的参数。

这会出现一个问题,每创建一个对象就需要在堆中开辟一块内存空间,但是里面保存的信息基本相同,因此十分浪费内存空间。

两个对象引用指向同一对象空间的内存图

在这里插入图片描述

对象在方法中的使用

使用对象类型作为方法的参数

任何数据类型都能作为方法的参数。

对象引用作为参数传递给方法的是对象的地址值

public class Demo04PassObjParam {
    public static void main(String[] args) {
        Phone one = new Phone();
        one.brand = "小米";
        one.price = 998.0;
        one.color = "土豪金";
        mothod(one); // 传递的对象的地址
        System.out.println(one);

    }

    public static void mothod(Phone param){
        System.out.println(param);
        System.out.println(param.brand);  // 苹果
        System.out.println(param.price);  // 998.0
        System.out.println(param.color);  // 土豪金
    }
}

在这里插入图片描述
在这里插入图片描述

使用对象类型作为方法的返回值

使用对象类型作为方法的返回值时,返回的是对象的地址值

public class Demo05PhoneReturn {
    public static void main(String[] args) {
        // 用对象类型接收返回值
        Phone two = getPhone();
        System.out.println(two.brand);  // 小米
        System.out.println(two.price);  // 799.0
        System.out.println(two.color);  // RoseGold
    }

    public static Phone getPhone() {
        Phone one = new Phone();
        one.brand = "小米";
        one.price = 799.0;
        one.color = "RoseGold";
        return one;
    }

}

在这里插入图片描述

成员变量和局部变量的区别

  1. 定义的位置不一样

    局部变量:在方法的内部

    成员变量:在方法的外部,直接写在类当中。

  2. 作用域不一样

    局部变量:所在方法中可以使用,出了所在方法就不能使用。

    成员变量:整个类全都可以通用

  3. 默认值不一样

    局部变量:没有默认值,要使用,必须先赋值

    成员变量:如果没有赋值,会有默认值,规则和数组一样。

  4. 内存的位置不一样

    局部变量:位于栈内存

    成员变量:位于堆内存。

  5. 声明周期不一样

    局部变量:随着方法进栈而创建,随着方法出栈而销毁。

    成员变量:随着对象创建而创建,随着对象被垃圾回收而消失。

  6. 权限修饰符的使用不同public、 protected、 缺省、 private

    局部变量:不能使用权限修饰符。

    成员变量:可以使用权限修饰符。

public class Demo01VariableDifference {

    String name; // 成员变量

    public void methodA(){
        int num = 20; // 局部变量
        System.out.println(num);
    }

    public void methodB(int param) { //参数就是局部变量
//      System.out.println(num); // 错误,num是methodA方法中的局部变量,不能在methodB中使用
        System.out.println(name);  // 成员变量,类中都可以使用
        int age;  // 局部变量
//      System.out.println(age);   // 局部变量未赋值不能使用
        // 参数在方法调用时,必然会被赋值
        System.out.println(param); // 这种写法没有问题
    }
}

练习

创建一个学生类,三个属性,学号,年级和成绩。

创建20个学生类,其中学号从1开始到20结束,年级和成绩随机赋值。

Student类

// Student类
package cn.study.day26.demo05;

public class Student {
    private int number = id;  // 学号
    private int state;        // 年级
    private int score;        // 成绩
    private static int id = 1;    // 自增id

    // 无参构造器
    public Student() {
        ++id;
    }
    // 有参构造器,number和id变量自增,不允许设置
    public Student(int state, int score) {
        this.state = state;
        this.score = score;
    }

    public String stuInfo() {
        String info = "学号:" + this.getNumber() + ", 年级:" +this.getState() + ", 成绩:" + this.getScore();
        return  info;
    }

    // Getter/Setter
    public int getNumber() {
       return this.number;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

工具类

// 工具类
package cn.study.day26.demo05;
public class Utility {
    // 遍历打印学生信息

    /**
     * @Description 遍历Student数组,并打印数组中学生对象的信息
     * @author Joker
     * @param stus  要遍历的数组
     */
    public static void traverseStu(Student[] stus) {
        for (int i = 0; i < stus.length; i++) {
            System.out.println(stus[i].stuInfo());
        }
    }


    /**
     * @Description 筛选出Student数组中指定年级学的信息,并打印。
     * @author Joker
     * @param state 需要筛选出来的年级
     */
    public static void searchStu(Student[] stus, int state) {
        for (int i = 0; i < stus.length; i++) {
            if (stus[i].getState() == state) {
                System.out.println(stus[i].stuInfo());
            }
        }
    }

    /**
     * @Description 使用冒泡排序算法,按照成绩属性给Student数组排序,从小到大。
     * @author Joker
     * @param stus  要排序的数组
     */
    public static void bubbleSortStus(Student[] stus) {
        for (int i = 0; i < stus.length - 1; i++) {
            boolean flag = true;
            for (int j = 0; j < stus.length - 1 - i; j++) {
                if (stus[j].getScore() > stus[j + 1].getScore()) {
                    Student temp = stus[j];
                    stus[j] = stus[j + 1];
                    stus[j + 1] = temp;
                    flag = false;
                }
            }
            if(flag){
                break;
            }
        }
    }

    // 按年级快速排序

    /**
     * Description 使用快速排序算法,按照年级属性给Student数组排序,从小到大
     * @author Joker
     * @param stus 要排序的数组
     */
    public static void sortStus(Student[] stus){
        quickSort(stus, 0, stus.length - 1);
    }

    // 快速排序
    private static void quickSort(Student[] stus, int low, int high) {
        int pivot = low;
        if(low < high) {
            pivot = partition(stus, low, high);
            quickSort(stus,low,pivot - 1);
            quickSort(stus,pivot + 1, high);
        }
    }

    // 确定基轴值位置
    private static  int  partition(Student[] stus, int low, int high) {
        int pivotKey = stus[low].getState();
        while(low < high) {
            while(low < high && stus[high].getState() >= pivotKey){
                high--;
            }
            swap(stus,low,high);
            while (low < high && stus[low].getState() <= pivotKey){
                low++;
            }
            swap(stus,low,high);
        }
        return low;
    }

    // 交换两个对象引用
    private static void swap(Student[] stus, int low, int high) {
        Student temp = stus[low];
        stus[low] = stus[high];
        stus[high] = temp;
    }
}

测试类

// 测试类
package cn.study.day26.demo05;
public class StudentTestDrive {

    public static void main(String[] args) {
        Student[] stus = new Student[20];
        for (int i = 0; i < stus.length; i++) {
            stus[i] = new Student();
            // stata = [1,6]
            // score = [0,100]
            // 随机数计算公式[a,b]
            // Math.random * (b - a + 1) * a;
            int state = (int) (Math.random() * (6 - 1 + 1) + 1);
            int score = (int) (Math.random() * (100 + 1));
            stus[i].setState(state);
            stus[i].setScore(score);
        }

        // 按年级筛选学生
        System.out.println("==========按年级筛选==========");
        Utility.searchStu(stus,3);


        // 按成绩冒泡排序
        System.out.println("==========按成绩排序==========");
      Utility.bubbleSortStus(stus);
        Utility.traverseStu(stus);  // 遍历打印学生信息


        // 按年级快速排序
        System.out.println("==========按年级排序==========");
        Utility.sortStus(stus);
        Utility.traverseStu(stus);   // 遍历打印学生信息
    }

}

方法

方法重载

概念

同一个类中,允许存在一个以上的同名方法,只要它们的参数个数、参数类型或者参数顺序不同即可。

特点

与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数、参数类型或参数顺序),调用时,可以根据传传递的实参类型、个数、顺序来调用对应的方法。

可变形参的方法

JavaSE5.0 中提供了VarArgs(variable number of arguments) 机制,允许直接定义和能多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。

格式

权限修饰符 返回值类型 方法名(数据类型 ... 参数名) {}

使用

  1. 当调用可变个数形参的方法时,传入的参数个数可以是 0,1,2... 多个

  2. 但是传入的参数必须与形参中的类型保持一致。

  3. 可变个数形参的方法与本类中方法名相同,参数列表不同的方法构成重载。

  4. 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。

  5. 可变个数形参在方法的形参中,必须声明在末尾

  6. 因此可变个数形参在方法的形参中,最多只能声明一个。

public class MethodVarArgsTest {

    public static void main(String[] args) {
        MethodVarArgsTest test = new MethodVarArgsTest();
        test.show(10);      // 重载方法1
        test.show("hello"); // 重载方法2
        test.show("hello","abcdef","12345"); // 可变个数形参方法
        test.show(); // 没有参数也可以调用可变形参方法
    }

    // 重载方法
    public  void show(int i){
        System.out.println("重载方法1");
    }

    public void show(String s) {
        System.out.println("重载方法2");
    }

    public void show(String ... str) {
        System.out.println("可变个数形参方法");
        // 使用时,把可变个数形参当作数组使用
        for(int i = 0; i < str.length;i++) {
            System.out.println(str[i]);  // 当作数组用
        }
    } 
    
    // 相同类型的数组会与可变类型方法 不能构成重载,会发生冲突。
    /*public void show(String[] strs) {
        
    }*/
    
    // 正确写法,必须声明在末尾
    public void show(int i, String ... str) {

    } 
    
    // 错误写法! Vararg parameter must be the last in the list
    /*public void show(String ... str, int i) {
        
    }*/
    
    
}

在这里插入图片描述

方法参数的值传递机制

在Java中方法的参数传递方式只有一种**值传递**,即将实际参数值的副本传入方法内,而参数本身不受影响。

  • 形参是基本数据类型:将实参基本数据类型变量的**数据值**传给形参。
  • 形参是引用数据类型:将实参引用数据类型变量的**地址值**传给形参。

练习

练习1

下面代码的输出结果是?

class Value {
    int i = 15;
}

public class TransferTest3 {
    public static void main(String args[]) {
        TransferTest3 test = new TransferTest3();
        test.first();   
    }
    
    public void first() {
        int i = 5;  
        Value v = new Value();
        v.i = 25;     
        second(v,i);   
        System.out.println(v.i);  // 20 【传递的是地址值】
    }
    public void second(Value v,int i) {
        // v = 25, i = 5
        i = 0;  // i = 0
        v.i = 20;  // v = 25
        Value val = new Value();
        v = val;  // v = 15
        System.out.println(v.i+" " + i); // 15 0
    }
}



练习2
// 下面代码的输出结果
public class ArrayPrintTest {
    int[] arr = new int[]{1,2,3};
    System.out.println(arr); // 地址值
    
    char[] arr1 = new char[]{'a','b','c'};
    System.out.println(arr1); // abc
    // println(char[]) 的重载方法,会遍历该char[] 并打印
}

递归方法

方法递归(recursion)包含了一种隐式的循环,它会重复执行某段代码,但是这种重复执行无须序循环控制。

递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。

/**
 * 递归方法的使用
 */
public class Demo01Recursion {
    public static void main(String[] args) {
        // 递归计算1-100所有自然数的和
        int n = 100;
        int sum =  getSum(n);
        System.out.println(sum);

        // 递归计算n!
        System.out.println(getFact(10));

        // 已知有一个数列 f(0) = 1, f(1) = 4, f(n+2) = 2 * f(n+1) + f(n), 求f(10) 的值
        // f(n + 2) = 2 * f(n + 1) + f(n);
        // f(10) = 2 * f(9) + f(8)
        // f(n) = 2 * f(n - 1) + f(n - 2);
        System.out.println(f(10));

        // 求第n个斐波那契数
        System.out.println(Fib(10));

    }
    //  求和
    public static int getSum(int n){
        if(n >= 1){
            return n + getSum(n-1);
        }
        return 0;
    }
    // 求阶乘
    public static int getFact(int n){
        return n == 1? 1 : n * getFact(n-1);
    }

    // 求f(n)
    public static int f(int n){
        if(n == 0){
            return 1;
        } else if(n == 1) {
            return 4;
        } else {

            return  2 * f(n - 1) + f(n - 2);
        }
    }

    // Fibonacci
    public static int Fib(int n){
        return n <= 2 ? 1 : Fib(n - 1) + Fib(n - 2);
    }

}

三大特征之封装

面向对象三大特征:封装继承多态

封装概述

概述

面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。

封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

程序设计追求:高内聚、低耦合

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

原则

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

体现

  1. 方法就是一种封装。
  2. 关键字private也是一种封装。
public class Demo02Method {
    public static void main(String[] args) {
        int[] arr= {1,2,3,4,5};
        int max = getMax(arr);
        System.out.println("最大值" + max);
    }
    public static int getMax(int[] arr){
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            max = arr[i] > max ? arr[i] : max;
         }
        return max;
    }
}
// 方法的调用者并不关心如何getMax()中的实现细节,它只是调用getMax()来完成获取数组最大值的功能。
// 将方法封装起来,就是隐藏细节,对外界不可见。

private关键字

private关键字用于修饰需要被保护的成员变量

使用说明

// 创建一个Person 类
public class Person {
    String name;
    int age;
    
    public void show(){
        System.out.println("My name is " + name + ". I'm " + age + " years old");
    }
}
// 在main方法中创建一个Person对象
public class Demo03Person {
    public static void main(String[] args) {
        Person person = new Person();

        // 对对象中的成员变量进行赋值
        person.name = "Joker";
        person.age = -18; // -18 不合理的数值,成员变量无法阻止这个不合法的数据被设置。
        person.show();
        // private就是用来保护成员变量被赋予这种不合理数值的。
    }
}

private关键字用来修饰成员变量,被修饰的成员变量,在本类中可以随意访问,但是超出本类范围之外就不能在直接访问

// 用private修饰 成员变量 age
public class Person {
    String name;
    private int age; 
    // 此时age 不能直接通过 对象名.成员变量名来访问
    public void show(){
        System.out.println("My name is " + name + ". I'm " + age + " years old");
    }
}

在这里插入图片描述

如果想要访问private修饰的成员变量,就需要使用间接访问的方法。

间接访问

间接访问private修饰的成员变量,就是在本类中定义一对**Getter/Setter方法**。

public class Person {
    String name;
    private int age;
    public void show(){
        System.out.println("My name is " + name + ". I'm " + age + " years old");
    }

    // Setter方法,专门用于设置age的数据
    public void setAge(int num){
        // 在Setter方法中加入判断条件,可以有效杜绝成员变量被赋予不合理的值。
        if(num <= 150 && num >= 0){
            age = num;
        } else{
            System.out.println("Error,the date of num is corrputed!");
        }
    }
    // Getter方法,专门用获取age的数据
    public int getAge() {
        return age;
    }
}
public class Demo03Person {
    public static void main(String[] args) {
        Person person = new Person();

        person.name = "Joker";
//        person.age = 18; // 此时需要访问age变量就不能使用直接访问的方法
        person.setAge(18); // 而是使用间接访问的方法,并将想赋予的值写在方法调用()中
        person.show();
        int JokerAge = person.getAge();  // 获取成员变量的值,也应该使用间接访问方法
        System.out.println("Joker's age is " + JokerAge);
    }
}

在这里插入图片描述

Setter方法

public void setXxx(para) {
    // 方法体
}

Setter方法必须有参数无返回值;参数类型与要被设置的成员变量保持一致。

命名规则:set + 变量名首字母大写。

Getter方法

public dataType getXxx() {
    // 方法体
}

Getter方法必须有返回值无参数,返回值类型与要设置的成员变量保存一致。

命名规则:get + 变量名首字母大写。

练习

利用primate关键字定义一个学生类

// 利用primate关键字定义一个学生类
public class Student {
    private String name;  // 姓名
    private short age;
    private boolean male;  // true为男,false 为女
    
    public void setName(String str){
        name = str;
    }

    public String getName(){
        return name;
    }

    public void setAge(short num){
        age = num;
    }
    public short getAge() {
        return age;
    }
    
    public void setMale(boolean b){
        male = b;
    }
    
    // boolean的Getter方法命名 应该是 isXxxx
    public boolean isMale() {
        return male;
    }
}

注意

基本数据类型中的boolean值,其Getter方法的命名一定要写成**isXxxx**

// 使用学生类创建对象
public class Demo04Student {
    public static void main(String[] args) {
        Student stu = new Student();

        stu.setName("张三");
        stu.setAge(18);
        stu.setMale(true);

        System.out.println("姓名:" + stu.getName());
        System.out.println("年龄:" + stu.getAge());
        String sex = stu.isMale()? "男" : "女";
        System.out.println("性别:" + sex);
    }
}

在这里插入图片描述

this关键字

当成员方法中的局部变量,和成员变量重名时,根据"就近原则",优先使用局部变量。

// 定义Person类
public class Person {

    String name; // 成员变量
    
    // 成员方法的局部变量名和成员变量名都是name
    public void sayHello(String name){ // 局部变量
        System.out.println(name + ",您好!我是" + name);
    }
}
// 使用Person类创建对象
public class Demo01Person {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "张三";
        person.sayHello("罗翔老师");
    }
}
// 结果是成员方法优先使用的是局部变量name

在这里插入图片描述

解决方法是使用this关键字。

public class Person {
    String name; // 姓名
    
    public void sayHello(String name){
        System.out.println(name + ",您好!我是" + this.name);
    }
}
// this.name 就相当于 person.name

在这里插入图片描述

谁调用的方法,this就指向谁。

public class Person {
    String name; // 姓名

    public void sayHello(String name){
        System.out.println(name + ",您好!我是" + this.name);
        System.out.println(this); // 在成员方法中打印调用者的地址。
    }
}
public class Demo01Person {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "张三";
        person.sayHello("罗翔老师");
        System.out.println(person);  // 打印对象名

		// 创建不同的对象
        System.out.println("========================");
        Person person1 = new Person();
        person1.name = "李四";   
        person1.sayHello("罗翔老师");   
        System.out.println(person1); // 打印对象名
    }
}

在这里插入图片描述

this 调用构造器

  1. 在类的构造器中,可以显式的使用this(形参列表)的方式,调用本类中指定的其他构造器。
  2. 构造器中不能通过this(形参列表)的方式来自己调用自己。
  3. 同时构造器之间不可以构成环形调用关系,如果一个类中有n个构造器,则最多有n-1个构造器中可以使用this(形参列表);
  4. 规定:this(形参列表)必须声明在当前构造器的首行,也就是构造器内部最多只能声明一个this(形参列表)
  5. 补充(了解):如果没有显式的在构造器中指定调用哪一个构造器,那么默认会调用super(),用来在子类实例化时先加载父类的结构。

构造器

构造器(constructor)是专门用来创建对象的一种结构,当一个对象被创建时候,构造器用来初始化该对象,给对象的成员变量赋初始值。当我们通过关键new来创建对象时,其实就是在调用构造器

tips:无论你与否自定义构造器,所有的类都有构造器,因为Java自动提供了一个空参构造器,一旦自己定义了构造器,Java自动提供的默认无参数构造器就会失效。

构造器的定义格式

修饰符 构造器名(参数类型 参数名称,...){
     // 方法体
}
// 构造器名与所在类名称完全一样!

注意事项

  1. 构造器的名称必须和所在的类名称完全一样,包括大小写也要一样。
  2. 构造器没有返回值类型,包括void。
  3. 构造器不能return一个具体的返回值。
  4. 如果没有自定义构造器,编译器会自动提供一个无参数构造器,格式如下:
public className() {} // 编译器默认提供的构造器
  1. 一旦定义了至少一个构造器,编译器提供的构造器将失效。
  2. 构造器可以进行重载,方法名相同,参数列表不同
// 定义一个类,在其中定义构造器
public class Student {
    // 成员变量
    String name;
    int age;


    // 构造器可以重载
    // 无参构造器
    public Student() { // 名字和类名完全一样
        System.out.println("无参构造器执行!");
    }

    // 全参构造器
    public Student(String name, int age) {
        System.out.println("全参构造器执行!");
        this.name = name;
        this.age = age;

    }

    // Setter/Getter 方法
    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 class Demo02Student {

    public static void main(String[] args) {
         // 构造器的调用通过new className();
         Student stu = new Student();           // 调用无参构造器,方法重载
        
		System.out.println("=============================");

         Student stu1 = new Student("张三",18); // 调用有参构造器,并进行初始化,方法重载
         System.out.println("姓名:" + stu1.getName() + " 年龄:" + stu1.age);

         System.out.println("=============================");
        
         // Setter方法用来对成员变量重新赋值
         stu1.setName("法外狂徒");   
         stu1.setAge(19);
         System.out.println("姓名:" + stu1.getName() + " 年龄:" + stu1.age);

    }
}

在这里插入图片描述

标准代码——JavaBean

一个标准的类同时需要拥有下面四个组成部分

  1. 所有的成员变量都要使用**private**关键字修饰。
  2. 为每一个成员编写一对**Getter/Setter**方法。
  3. 编写一个无参数的构造器
  4. 编写一个全参数的构造器

这样一个标准的类也被称为 Java Bean

public class ClassName{
	//成员变量
	//构造器
	//无参构造器【必须】
	//有参构造器【建议】
	//成员方法
	//getXxx()
	//setXxx()
}

举例

// 定义一个标准的学生类
public class Student {
    // 成员变量
    private String name; // 姓名
    private int age;     // 年龄

    // 自动生成的无参构造器
    public Student() {
    }

    // 自动生成的全参构造器
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    
    // 自动生成的Getter / Setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
//使用类
public class Demo01Student {
    public static void main(String[] args){

        Student stu1 = new Student();   // 调用无参构造器
        stu1.setName("张三");           // 使用Setter方法赋值
        stu1.setAge(18);
        // 使用Getter方法获取值
        System.out.println("姓名:" + stu1.getName() + ",年龄:" + stu1.getAge());

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

        Student stu2 = new Student("李四",19); // 调用全参构造器
        System.out.println("姓名:" + stu2.getName() + ",年龄:" + stu2.getAge());

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

        stu1.setName("法外狂徒");                          // Setter方法修改值
        stu1.setAge(99);
        System.out.println("姓名:" + stu1.getName() + ",年龄:" + stu1.getAge());
    }
}

static

static主要修饰类的内部结构:属性方法代码块内部类

static修饰的内部结构,会随着类的加载而加载

修饰属性

static修饰的属性,称作静态变量

  1. 随着类的加载而加载
  2. 在程序运行期间只会被加载一次
  3. 属于类不属于对象。(权限运行,对象可以调用)
  4. 存在于方法的静态域中。

使用场景

  1. 当该属性可以被多个对象共享时。例如: 国籍、教室等公共的属性。
  2. 类中的常量,经常被static修饰。

static内存图

在这里插入图片描述

修饰方法

static修饰的方法,被称作静态方法

  1. 随着类的加载而加载
  2. 静态方法中,只能调用静态的方法或属性
  3. 非静态方法中,既可以调用静态的方法或属性、也可以调用非静态的方法或属性。
  4. 在静态的方法内,不能使用thissuper关键字

使用场景

  1. 方法中如果需要操作静态属性,同常设置为静态方法
  2. 工具类中的方法,习惯上声明为static的。比如:Math、Arrays、Collections

修饰代码块

staitc修饰的代码块称为静态代码块。

静态代码块

  • 内部可以有输出语句。
  • 随着类的加载而执行
  • 只会在类加载的时候,执行唯一一次
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
  • 静态代码块内只能调用静态的属性静态的方法不能调用非静态的结构
  • 作用:初始化静态属性

点击全文阅读


本文链接:http://zhangshiyu.com/post/30569.html

方法  变量  成员  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1