文章目录

  • 1. 啥是封装 ?
  • 1.1 封装好处
  • 1.2 权限修饰符
  • 1.2.1 测试权限,在相同包下
  • 1.2.2 测试权限,在不相同包下
  • 1.3 Get()方法和Set()方法使用
  • 1.4 封装并不单纯指 private
  • 1.5 课堂练习:封装学生类信息
  • 2. 构造函数
  • 2.1 概述
  • 2.2 语法结构
  • 2.3 构造方法的使用
  • 3. 代码块(静态代码块,构造代码块,局部代码块)
  • 3.1 构造代码块
  • 3.2 局部代码块
  • 3.3 静态代码块
  • 3.4 代码块的执行顺序
  • 4. this关键字
  • 4.1 概述
  • 4.2 使用场景
  • 4.2.1 练习:区分变量名相同
  • 4.2.2 练习:构造方法调用
  • 4.3 比较两个人的名字是否相同


1. 啥是封装 ?

  1. 上一节了解了java中重要的概念,类和对象,也就算入门了思想编程阶段了,接下来也属于的编程思想上的延伸,我们java的核心思想是面向对象操作,既然是面向对象,就要了解面向对象的三大特征也是核心思想,封装,继承,多态。
  2. 那么什么是封装 ?封装是指将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来对隐藏的信息进行操作和访问。
  • 可以理解为是将 属性和方法封装起来,而将属性和方法封装起来的载体就是 类。
  1. 列举生活中的一些例子:
  • 开车, 我们只要学会开就可以,不需要了解发动机是如何驱动的。
  • 电插座, 只需要知道如何使用即可,不需要直到里面电路集成原理。

1.1 封装好处

  1. 封装的好处: 保证了类的数据结构的完整性,使用该类,的用户不能轻易的操作数据结果,只允许操作公开的数据,就避免了对内部数据的影响,提高了程序的可维护性。
  • 只能通过规定的方法去访问数据。
  • 隐藏了实例细节,增加了数据安全性。
  1. 总结: 相当于把 功能封装进对象, 强调,对象具备了这样的功能! 将变化隔离,提高重用性、提高安全性!

1.2 权限修饰符

  1. 用来控制类和类的 成员变量 以及 成员方法 的方法范围。
  • default :是没有修饰属性的时候,有默认为修饰。 只有同包类可以调用,子类不行。

修饰符

本类

同包其他类和子类

不同包的类或子类

private

可见

看不可

看不见

protected

可见

可见

看不见

default(默认)

可见

可以(子类看不见)

看不见

public

可见

可见

可见

1.2.1 测试权限,在相同包下

  1. 在相同的包下,在这里插入代码片
package com.oop.var;

/**
 * 人类的属性
 *      实际开发中属性都是私有的private的。
 */
public class VarTest {

    private String name;  // 姓名

    protected int age; // 年龄

    char sex; // 性别  '男',‘女’

    public String address; //地址


    /**
     * 测试方法 : 吃  喝   玩   乐
     */

    private void eat(){
        System.out.println("方法: private eat输出");
    }

    void drink(){
        System.out.println("方法: 默认 drink输出");
    }

    public void  play(){
        System.out.println("方法: public play输出");
    }

    protected void happy(){
        System.out.println("方法:protected 输出 ");
    }

}
  • 相同包的测试类。
package com.oop.var;

public class VarTest01 {
    public static void main(String[] args) {
        //测试 同包 不同类
        VarTest vt3 = new VarTest();

        //方法 测试
        vt3.play(); //玩方法public
        vt3.drink(); // 默认
        vt3.happy(); // protected 修饰

        //属性 测试
        System.out.println(vt3.age);
        System.out.println(vt3.sex);  // 默认输出为 空字符
        System.out.println(vt3.address);

    }
}
  • 输出结果:
方法: public play输出
方法: 默认 drink输出
方法:protected 输出 
0
 
null

1.2.2 测试权限,在不相同包下

  1. 在不相同的包下测试权限范围。 上面接VarTest 类。
package com.oop.var2;

import com.oop.var.VarTest;

/**
 * 不同包 测试权限修饰
 *      public private protected 默认default
 */
public class VarTest2 {
    public static void main(String[] args) {
        // 使用类的对象 就需要实例化 new
        VarTest vt2 = new VarTest();
        //不同包里面只有public可以看见
        System.out.println(vt2.address);

        /*方法测试*/
        vt2.play();   // 直接输出方法,因为没有返回值

    }
}
  • 输出结果:
null
方法: public play输出

1.3 Get()方法和Set()方法使用

  1. 信息时代用户信息很重要,私有变量无法访问,关键字 private 去私有化变量,如果无法访问属性怎么办? 只能通过公共访问方法;
  2. 下面封装用户的信息。
/**
 * 用户类
 */
public class User {
    // 用户属性
    private String userName;  //private 私有用户 
    private int  age; // private 私有年龄

    //对外提供方法的方法 get方法
    public String getUserName(){
        return userName;
    }

    // 对外提供修改方法  set方法 
    public void setUserName(String name){
        userName=name; //相当于 this.name = name;
    }
  // 年龄对外提供
    public void setAge(int age){
        // 进行封装内部处理 ,来处理负数的问题
        if (0<=age||age>=100){
            userAge =age;
        }else{
            System.out.println("输入错误,请从新输入");
        }
    }

    public int getUserAge(){
        return userAge;
    }
}
  • 测试类:
  1. 只有对外提供方法,才能访问私有变量;
public class UserTest {
    public static void main(String[] args) {
        User u = new User(); //创建对象
        String userName = u.getUserName();
        System.out.println(userName);

        u.setUserName("周杰伦");
        System.out.println(u.getUserName());

       //如果设置 int 为负数?
        u.setAge(-20); // 年龄为负数?? 怎么办?
        System.out.println(u.getUserAge()); // 输入0 是因为默认值
    }
}

输出结果:

null
周杰伦
输入错误,请从新输入
0  // 在调用了一次 getUserAge() 默认值

1.4 封装并不单纯指 private

  1. 封装 并不是单纯指使用权限修饰符修饰属性和方法, 更广义的意思指将某些复杂的功能集成起来形成模块化,让使用者调用该模块即可。
  • 其作用增加了代码的复用性。
  1. 如案例:数组之前学过的根据元素查询该元素下的索引。
public class ArrayDemo {
    public static void main(String[] args) {

        //1.定义数组
        String[] arr = {"张三","李四","王五","赵六"};
        System.out.println("请输出查询元素: ");
        String arr2 = new Scanner(System.in).next();//匿名对象使用。

        //2.业务逻辑处理,如何通过元素获取下标。
        for (int i = 0; i <arr.length ; i++) {
           //2.1 判断
            if (arr2.equals(arr[i])){
                System.out.println(i);
                break;//如果查询出,跳出即可
            }
        }
    }
}
  • 这样的代码,没有将核心代码进行封装,造成了复用率低,使用者如果要查询索引,都得写一遍这个代码。并且核心代码也暴露了在外面。所以 广义上得封装,就是将核心代码封装起来对外提供访问方法即可。
public class ArrayDemo {
    public static void main(String[] args) {
        String[] arr = {"张三","李四","王五","赵六"};
        int resault = new Utils().seach_Index(arr, "王五"); //通过这一句话就可以调用。
        System.out.println(resault);
    }
}

//1.将方法进行封装。
class Utils{
    /**
     *
     * @param o 数组名
     * @param o1 传入查询元素
     * @return int 类型 -1没有查询到。
     */
    public  int seach_Index(Object[] o, Object o1 ){
        for (int i = 0; i <o.length ; i++) {
            if (o1.equals(o[i])){
                return i;
            }
        }
        return -1; //返回-1就是没有
    }
}

1.5 课堂练习:封装学生类信息

  1. 通过上述学习的封装思想,将学生类必要的属性封装起来,方便创建对象,调用对象使用。oop思想。
  • 使用get()和set()方法对外提供访问。
public class Students {
    //1. 私有化属性
    private String name;//姓名
    private int age;//年龄
    private String adress; //地址

    //2.对外提供访问方法get和set方法
    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 String getAdress() {
        return adress;
    }

    public void setAdress(String adress) {
        this.adress = adress;
    }

    //3. 封装自己独特的方法例如 介绍自己
    public void introduce(){
        System.out.println("我的名字叫"+name+",年龄 "+age+",家在"+adress);
    }

}
  • 测试类,同包下。
public class Student_Test {
    public static void main(String[] args) {
        //1.创建对象1
        Students s = new Students();
        int age = s.getAge();
        System.out.println(age); //返回值是0,因为什么?

        //2.给属性赋值 通过set方法
        s.setName("张三");
        s.setAge(18);
        s.setAdress("北京");
        s.introduce();

        //2.创建对象2
        Students s2 = new Students();
        s2.setName("李四");
        s2.setAge(30);
        s2.setAdress("上海");
        s2.introduce();

        
    }
}

2. 构造函数

2.1 概述

  1. 构造方法和它所在类的名字相同,注意:不用定义返回值类型,即不用 void 修饰
  2. 当一个对象被创建时候,就会 自动调用默认的空参构造方法
  • 不管你是否自定义构造方法,所有的类都有默认的 空参构造方法,因为 Java 自动提 供了一个默认构造方法, 默认构造方法的访问修饰符和类的访问修饰符相同 (类为 public,构造函数也为 public;类改为 protected,构造函数也改为 protected)。
  • 一旦你定义了自己的构造方法(如含参数),默认的空参构造方法就会失效。
  1. 构造方法的作用:即给重要属性赋初始值。

2.2 语法结构

  1. 构造函数可以有参数,也可以没有参数。
  2. 默认的是空参数构造方法。
  3. 构造方法可以重载 (方法名相同,参数不同)
//修饰符 如果没有就是默认 default  
	修饰符 方法名(参数){ //方法名必须与类名一致。参数可由可无
		初始化;
	}

2.3 构造方法的使用

  1. 构造方法的作用是什么 ? 什么时候调用构造方法?
  • 创建对象时,即new 会调用默认的空参构造方法,进行初始化赋值。
public class Student {
    private String name;
    private  int age;

    /**
     * java提供了一个默认的构造方法;
     */
    //1.空参数构造
    public Student() {
        //自己定义
        System.out.println("我是构造方法");
    }

    //2.一个参数构造
    public Student(String name) {
        //同时给可以赋值
        //age=10; 也可以给属性初始化值
        this.name = name;
    }

    //3.多参数构造
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //普通方法,输出属性
    public void introduce(){
        System.out.println("name="+name+" , age= "+age);
    }

	//main 方法程序入口
    public static void main(String[] args) {
        //1,调用的是无参数构造方法
        Student s1 = new Student();
        s1.introduce();

        //2.调用的是含参数构造方法
        Student s2 = new Student("张三", 30);
        s2.introduce();

        //3.调用的是单个参数构造方法
        new Student("李四").introduce();


    }
}
  • 输出结果:
我是构造方法
name=null , age= 0
name=张三 , age= 30
name=李四 , age= 10

3. 代码块(静态代码块,构造代码块,局部代码块)

  1. 啥叫代码块? 就是用 { }括起来的代码块;
  • 根据位置不同,分构造代码块 和 局部代码块。
  • 根据修饰符不同,如果被static关键字修饰的代码块,叫静态代码块,随着类的加载而加载。
// Person{} 就是一个代码块 ,即{}就是代码块
class Person{
	public static void main(String[] args){

	}
}

3.1 构造代码块

  1. 构造代码块 。
  • 位置: 在 类的内部,方法外部,的代码块。
  • 作用: 通常用于抽取 构造方法中的共性代码。
  • 加载顺序:每次调用构造方法前都会调用构造代码块,优先于构造方法加载
  1. 构造代码块案例。
public class Person {
    private String name; //名字
    private String country; //国家
    private String city; // 城市


    //4. 构造代码块,
    {
        country="中国";//初始化成员变量
        System.out.println("语言:汉语");
    }

    //5.set和get方法
    public void setCountry(String country) {
        this.country = country;
    }
    public String getCountry() {
        return country;
    }

    //1.空参构造方法
    public Person() {
        System.out.println("语言:汉语");
    }


    //2.带多个参数构造方法
    public Person(String name, String country, String city) {
        this.name = name;
        this.country = country;
        this.city = city;
        System.out.println("语言:汉语");
    }

    //3.带一个参数的构造方法
    public Person(String country) {
        this.country = country;
        System.out.println("语言:汉语");
    }

    public static void main(String[] args) {
        Person p = new Person();
        //new Person("中国");
        //没有调用set()方法进行赋值。会输出什么?
        System.out.println(p.country);//输出中国,由构造代码块提前赋值。
        p.setCountry("China");
        System.out.println(p.getCountry());//输出China,有set方法更改了值。
    }

}
  • 输出结果:
语言:汉语
语言:汉语
中国
China

3.2 局部代码块

  1. 局部代码块。
  • 位置: 在方法里面的代码块。
  • 作用: 通常用于控制变量的作用范围,出了括号就失效。
  • 加载顺序: 构造代码块是最优先的,然后局部代码块当方法调用时才会执行。
  1. 局部代码块。
public class Person2 {
    private  int age;

    //1.普通方法
    public void init(){

        {
            int age=10;//优先于加载局部代码块的值age
            System.out.println("我是局部代码块 "+age);
        }
        System.out.println(age);// 成员变量的age
    }

    public static void main(String[] args) {
        Person2 p = new Person2();
        p.init();

    }
}
  • 输出结果:
我是局部代码块 10
0

3.3 静态代码块

  1. 被关键字 static修饰的代码块,就是静态代码块。
  • 位置: 在类里,方法外。
  • 作用: 一般用于加载项目驱动(加载配置文件),或者项目初始化。
  • 加载顺序: 优先于类的加载而加载,只加载一次。
  1. 静态代码块。
public class Person3 {
    //private  String IP;//ip地址
     private static  String hostName;// 主机地址
    //1.空参构造方法
    public Person2() {
        System.out.println("我是构造方法");
    }

    //2.作用,在类的加载之前加载,提前加载配置文件。
    static {
        hostName ="192.168.1.1";//静态代码块只能给静态属性赋值;
        System.out.println("我是静态代码块");
    }


    public void conn(){
        String ip ="192.168.1.1";//数据接口
        if (ip.equals(hostName)){
            System.out.println("连接成功");
        }else {
            System.out.println("连接失败");
        }

    }

    public static void main(String[] args) {

        new Person3().conn();
        System.out.println("-----------");
        new Person3();//第二次就不会调用,只加载一次。

    }
}
  • 输出结果:
我是静态代码块
我是构造方法
连接成功
-----------
我是构造方法

3.4 代码块的执行顺序

  1. 静态代码块 > 构造代码块> 构造方法>局部代码块
public class Person4 {

    public void init(){
        {
            System.out.println("局部代码块");
        }
    }

    {
        System.out.println("构造代码块");
    }

    static{
        System.out.println("静态代码块");
    }

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

    public static void main(String[] args) {
        new Person4();

        //1.局部代码块只有在调用方法时才会执行
        // new Person4().init();
    }
}
  • 输出结果:
静态代码块
构造代码块
构造方法

4. this关键字

4.1 概述

  1. java里面 this 是指 本身 的意思,当前类,本类对象的一个引用对象。
  2. 形参与成员变量重名时,可以用this关键字来区分?
  • 是不是很熟悉这句话?哪见过? set() 和 get() 方法。
  1. 只能在构造函数中使用。
  • this(); 必须放在第一行。

4.2 使用场景

4.2.1 练习:区分变量名相同

  1. 区分同名参数,this 相当于本类调用。
public class Test_this {

    private String name;

    //构造方法
    public Test_this(){
        System.out.println("空参构造方法");
    }

    //1.类似于 set赋值方法。
    public void setName1(String name1){
        name = name1; // 给成员变量赋值
    }

    public void setName(String name) {
        //形式参数名称和成员变量名称相同时,使用this区别,相当于 Test_this.name=name;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //2. 普通方法
    public void info(){
        System.out.println(this.getName());//相当于 Test_this.getName();
    }

    public static void main(String[] args) {
        new Test_this();
        Test_this t = new Test_this();
        t.setName1("张三");
        //打印输出name值
        System.out.println(t.getName());
        t.info();


    }
}
  • 输出结果:
空参构造方法
空参构造方法
张三
张三

4.2.2 练习:构造方法调用

  1. this(参数),相当于调用类中的构造方法, 但是必须放在第一行。
  2. 并且在类中,只能出现一个this()
  • 不能同时在两个构造方法中使用this();
public class Test_this {

    private String name;

    //1.空参构造方法
    public Test_this(){
        this("张三"); //只能出现一个this()引用构造函数。
        System.out.println("空参构造方法");
       // this(""); //必须放在首行。
    }

   //2.含参数构造方法
    public Test_this(String name) {
        //this();  //只能出现一个this();引用的构造函数
        this.name = name;
        System.out.println("含参数构造函数");

    }

    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        String name = new Test_this().getName();//通过调用含参构造方法赋值
        System.out.println(name);
    }
}
  • 输出结果:
含参数构造函数
空参构造方法
张三

4.3 比较两个人的名字是否相同

  1. 创建两个对象比较它们之间的年龄是否相等。
  • 使用this 关键字。
public class Test_this {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    //2.当使用this之后的写法
    public Boolean compare2(Test_this t){
        return this.getAge() == t.getAge();//不同包下可以方法

        //return this.age == t.age;  //本类方法私有。
    }

    public static void main(String[] args) {
        Test_this t = new Test_this();
        t.setAge(18);

        Test_this t2 = new Test_this();
        t2.setAge(18);



        Boolean compare = t.compare2(t2);
        System.out.println(compare);
    }
}