• 04.封装


    4. 封装

    4.1 java代码中的封装:

    1. 函数:

      封装一段具体实现功能的代码;

    2. 类:

      封装了同一类事物的共有的属性(成员变量)和行为(函数);

      封装可以提高代码复用性,降低开发和维护的难度;

    可以隐藏事物的细节,提高安全性、易用性和美观性;还可以提高代码的复用性;

    ##4.2 权限修饰符

    1. private

      表示被修饰的成员(成员变量、函数)是私有的,只能在定义它的类中使用,不能被其他地方使用;注意:不能修饰类(外部类)

    2. public

      • 表示被修饰的成员是公开的,所有地方都能使用;
      • public可以修饰成员变量、函数和类,如果修饰类,这个类的类名必须和java的文件名一致;
        • 一个java文件中可以写多个类,但最多只能由一个public的类;
    3. protected

      • 基类的 protected 成员是包内可见的,并且对子类可见;

      • 若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。

        package p2;
        class MyObject2 {
        	protected Object clone() throws CloneNotSupportedException{
        	return super.clone();
        	}
        }
        
        package p22;
        public class Test2 extends MyObject2 {
        	public static void main(String args[]) {
        	MyObject2 obj = new MyObject2();
        	obj.clone(); // Compile Error         ----(1)
        
        	Test2 tobj = new Test2();
        	tobj.clone(); // Complie OK         ----(2)
        	}
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17

        对于(1)而言,clone()方法来自于类MyObject2本身,因此其可见性为包p2及MyObject2的子类,虽然Test2是MyObject2的子类,但在Test2中不能访问基类MyObject2的protected方法clone(),因此编译不通过;对于(2)而言,由于在Test2中访问的是其本身实例的从基类MyObject2继承来的的clone(),因此编译通过。

      注意:不能修饰类(外部类)

    4. default
      (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。

    封装,就是包装,主要用来隐藏事物的实现细节,提高程序的安全性;如果外界需要访问被封装的属性,需要对外提供公开的getter和setter函数用public

    4.3 构造函数

    1. 构造函数,又叫做构造器,就是在对象创建的时候由JVM自动调用的函数,创建对象都需要调用构造函数

    2. 作用:

      1. 初始化,在创建对象的过程中为成员变量赋值
      2. 前置动作,创建对象前的铺垫动作
    3. 格式:

      1.修饰符
      2.方法名:与类同名
      3.形参列表
      4.方法体	为属性/成员变量赋值
      格式:
      	1 2(3){
      	   4
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    4. 举例

      /*
      	构造函数的定义和使用:
      
      	存在的意义,创建对象的过程中为属性赋值;
      	让属性赋值的时机提前了
      */
      class Student{
      	//属性
      	String name;
      	int age;
      	/*
      		定义两个参数的构造方法
      	*/
      	public Student(String n,int a){
      		name = n;
      		age = a;
      	}
      	//方法
      	public void getInfo(){
      		System.out.println("姓名:" + name + ",年龄:" + age);
      	}
      }
      
      class TestStudent 
      {
      	public static void main(String[] args) 
      	{
      		//创建学生对象
      		//Student s = new Student();
      
      		//调用两个参数的构造方法创建Student对象,并且在创建对象的过程中为name、age属性赋值
      		Student s = new Student("李雷",20);
      
      		//以下操作属性属于后天给值
      		/*
      		s.name = "韩梅梅";
      		s.age = 19;
      		*/
      		s.getInfo();
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
    5. 注意事项

      一个类中,如果不显式的定义构造方法,编译器默认提供无参构造方法;

      一旦定义了构造方法,编译器将不再提供默认无参构造

      构造方法可以重载

      class Animal
      {
      	String brand;
      	int age;
      	
      	public Animal(String b,int a){
      		brand = b;
      		age = a;
      	}
      	public Animal(){
      	
      	}
      }
      
      class TestAnimal
      {
      	public static void main(String[] args) 
      	{	
      		//创建动物对象(使用两个参数的构造)
      		Animal a = new Animal("狗",3);
      		//创建动物对象(使用空参数的构造)
      		Animal a1 = new Animal();
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24

    4.4 this

    this:表示对自身所属对象的引用

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zHSUckDa-1656645884732)(./assets/015-this%25E5%2585%25B3%25E9%2594%25AE%25E5%25AD%2597.png)]

    作用:

    1. 记录当前正在创建或者使用的对象的内存地址

      /*
      	this的第一个作用:
      			记录当前正在创建或者使用的对象的内存地址
      */
      class Student
      {
      	//属性
      	String name;
      	int age;
      
      	public Student(String n,int a){
      		name = n;
      		age = a;
      		System.out.println("我是Student类中的构造方法..this=" + this);
      	}
      
      	//打印信息
      	public void info(){
      		System.out.println(name + "-->" + age);
      		System.out.println("我是Student类中的info方法..this=" + this);
      	}
      }
      
      class TestStudent
      {
      	public static void main(String[] args) 
      	{
      		//创建Student类的对象
      		Student s = new Student("李雷",20);
      		System.out.println(s);
      		s.info();
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
    2. 区分成员变量和局部变量

      /*
      	this的第二个作用:
      			区分成员变量和局部变量
      */
      class Person
      {
      	private String name;
      	private int age;
      	private char gender;	//性别
      
      	//构造方法(三个参数)
      	public Person(String name,int age,char gender){
      		this.name = name;
      		this.age = age;
      		this.gender = gender;
      	}
      
      	//getter&setter
      	public String getName(){
      		return name;
      	}
      
      	public void setName(String name){
      		this.name = name;
      	}
      
      	//打印信息
      	public void info(){
      		System.out.println(name + "-->" + age + "-->" +gender);
      	}
      }
      
      class TestPerson 
      {
      	public static void main(String[] args) 
      	{
      		//创建对象
      		Person p = new Person("韩梅梅",19,'女');
      		p.info();
      	}
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
    3. 构造方法之间相互调用

      【注意事项】:

      1. 构造方法之间使用this进行调用(构造方法可以重载)
      2. 记住以下4种情况:
        • 构造方法可以调用构造方法
        • 构造方法可以调用一般方法
        • 一般方法不可以调用构造方法
        • 一般方法可以调用一般方法
      3. 构造方法之间相互调用不能形成回路
      4. 构造方法的调用只能出现在首行,意味着只能有一个this存在
      class Teacher
      {
      	String name;
      	int age;
      	String address;	//籍贯
      
      	//构造方法(3个)
      	public Teacher(String name,int age,String address){
      		this(name,age);
      		//this.name = name;
      		//this.age = age;
      		this.address = address;
      		System.out.println("我是Teacher类中三个参数的构造..this=" + this);	//④
      	}
      
      	//构造方法(2个)
      	public Teacher(String name,int age){
      		//this.name = name;
      		/*
      			调用一个参数的构造,让其完成对name属性的赋值操作
      			错误: 找不到符号
      			原因:以下的调用方式属于一般方法的调用,不适合构造方法
      			Teacher(name);
      		*/
      		this(name);
      		this.age = age;
      		/*
      		错误: 对this的调用必须是构造器中的第一个语句
      		理解:构造函数的调用必须是在首行
      		this(name);
      		*/
      		System.out.println("我是Teacher类中两个参数的构造..this=" + this);	//③
      	}
      
      	//构造方法(1个)
      	public Teacher(String name){
      		//调用本类重载的空参构造
      		this();
      		this.name = name;
      		System.out.println("我是Teacher类中一个参数的构造..this=" + this);		//②
      	}
      
      	//构造方法(空参)
      	public Teacher(){
      		/*
      		错误: 递归构造器调用
      		构造方法之间相互调用不能形成回路
      		this("闫校",40,"山西");
      		*/
      		/*
      			尝试在构造方法中调用一般方法
      			可以
      		*/
      		show();
      		System.out.println("我是Teacher类中空参数的构造..this=" + this);		//①
      	}
      
      	public void show(){
      		System.out.println("我是一般方法show..");
      	}
      
      	public void func(){
      		/*
      			尝试在一般方法中调用构造方法
      			不可以
      		*/
      		//this();
      		System.out.println("我是一般方法func..");
      	}
      }
      
      class TestTeacher 
      {
      	public static void main(String[] args) 
      	{
      		//创建对象(匿名对象)
      		new Teacher("老郭",20,"上海");
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79

    4.5 Static

    4.5.1 静态属性

    1. static关键字修饰属性称为:静态属性、类属性

    2. 核心:与类有关,与对象无关

    3. 如果某个属性的值是固定的,将其定义为static修饰;所有对象公用;节省内存

    4. 格式:直接将static关键字写在成员变量的数据类型前面

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NNOhMtCz-1656645884734)(./assets/wps1.jpg)]

    5. 使用方法:静态成员变量和类的对象无关,直接通过类名调用

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5oTL3ZC-1656645884735)(./assets/wps2.jpg)]

    6. 特点:一个类中的静态成员变量,在这个类的所有对象中共享

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-crMlOE3C-1656645884736)(./assets/wps3.jpg)]

    7. 静态成员变量和非静态成员变量的区别:

      静态成员变量非静态成员变量
      保存位置方法区的静态区域堆内存的对象空间中
      书写格式需要使用static关键字修饰,将static关键字直接写在数据类型前面不需要使用static关键字修饰
      生命周期类加载的时候就分配空间和赋值;直到这个类被卸载(或者整个程序结束)创建对象的时候才分配空间和赋值;对象成为垃圾空间被回收的时候
      使用可以直接通过类名使用,和类的对象无关必须通过类的对象使用
      修改后的影响范围所有对象都影响只对这一个对象有影响

    4.5.2 静态方法

    1. 概念:static修饰的函数

    2. 格式

      public static void main(String args){
       System.out.println("this is a static method!");
      }
      
      • 1
      • 2
      • 3

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qVtxlBHP-1656645884736)(./assets/wps4.jpg)]

    3. 使用方法:静态函数和类的对象无关,直接通过类名调用

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YuV5lwDl-1656645884737)(./assets/wps5.jpg)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GJJqwixn-1656645884738)(./assets/wps6.jpg)]

    4. 内存原理

      java程序的内存划分:

      寄存器;本地方法区;方法区;栈内存;堆内存;

      方法区:主要保存静态成员、class、常量等一些东西;

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7wbhfun-1656645884738)(./assets/wps7.jpg)]

    5. 注意事项

      1. 静态函数不能调用非静态函数和非静态成员变量

        原因:

        非静态函数和非静态成员变量必须依赖类的对象使用;

        而静态函数使用不需要对象,所以在静态函数中不能直接调用非静态函数和非静态成员变量

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lmQcEavq-1656645884739)(./assets/wps8.jpg)]

      2. 非静态函数可以调用静态函数

        原因:

        非静态函数只能通过类的对象使用;如果可以调用非静态函数,说明此时已经存在对象;已经存在对象,说明类已经加载完毕;​类已经加载完毕,所以静态函数肯定可以使用

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Av7StV4h-1656645884740)(./assets/wps9.jpg)]

      3. 构造函数不能是静态的

        因为构造函数是在创建对象的时候用来给对象的成员变量赋值用的;如果构造函数是静态的,不需要对象就能使用,没有意义

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b4mbOAB7-1656645884740)(./assets/wps10.jpg)]

      4. 静态函数中不能使用和对象有关的关键字

        例如this,就是表示一个对象的引用的,而静态函数是没有对象就可以直接使用的,所以不能在静态函数里面使用this等关键字;

        还有一个关键字:super

    static的注意事项:

    首先要理解类和对象在内存中的生命周期现象(早、晚问题)

    类加载要远远早于对象加载 --> 类现有、对象后有

    通过以上的观点,得到:

    1. 类名可以调用静态成员(属性、方法) --> 同一生命周期
    2. 类名不可以调用非静态成员(属性、方法) --> 早加载的不能调用晚加载的
    3. 对象名可以调用非静态成员(属性、方法) --> 同一生命周期
    4. 对象名可以调用静态成员(属性、方法) --> 晚加载的可以调用早加载的

    4.6 代码块

    代码块,就是使用大括号括起来的一段代码;

    书写格式:

    class Test{
        {
    		代码;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    静态代码块

    作用:随着类的加载,一并加载到内存中,并且只加载一次

    好处:将某些依赖对象/容器的创建时机提前

    格式:

    class test{
        static{
    		//定义的代码
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:一般在开发中,静态代码块都要写在类的下面

    作用:

    因为在类加载完成时,静态代码块已经执行结束,某些需要提前完成的工作,可以放在静态代码块中执行

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vNcYM5H-1656645884741)(./assets/wps12.jpg)]

    构造代码块

    存在于类中,方法体外的局部代码块

    作用:将多个构造函数中相同的代码抽取到构造代码块中,在创建对象的过程中,构造代码块随着每个对象的创建都会执行一次

    优点:增强代码复用性

    格式:

    class test{
        {
    		//定义代码
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fg2XR4Bl-1656645884742)(./assets/wps13.jpg)]

    局部代码块

    作用:用来限制变量的使用范围

    格式:

    class test{
        public void func(){
            {	
    			//定义代码
    		}
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    补充:虽然格式和构造代码块一模一样,但是构造代码块存在于类的成员位置;而局部代码块存在于方法体中;

  • 相关阅读:
    Spring Cloud:三【详细】
    表单与列表在HTML与CSS中是这么玩的
    目标检测YOLO实战应用案例100讲-基于YOLOv3多模块融合的遥感目标检测
    (附源码)springboot火车票售卖系统 毕业设计 211004
    【数据结构】:队列的实现
    SAP ABAP 各模块的BAPI函数汇总
    Error: no matching distribution found for tensorflow-cpu==2.6.*
    新建一个默认的React项目
    【Computer Composition】Part1 计算机系统概述小结
    解决用Fiddler抓包,网页显示你的连接不是专用/私密连接
  • 原文地址:https://blog.csdn.net/qq2512446791/article/details/125555456