【类与对象JAVA(详)】(二)封装、构造方法、代码块

博主头像

🌠个人主页 : @赶路人- -
🌌个人格言 :

要努力成为梧桐,让喜鹊在这里栖息。
要努力成为大海,让百川在这里聚积。

7.display,vt.显示,显示器 [dɪˈsple] 8.set,v.设置,n.集合 [sɛt]

1.封装

什么是封装?
封装(Encapsulation)是面向对象编程中的一种基本概念,指的是将对象的内部状态和行为封装起来,对外只暴露必要的接口或方法,以保证数据的安全性和完整性,同时隐藏实现细节,方便后续的维护和扩展。

在Java中,封装通常通过使用访问修饰符(Access Modifiers)来实现。Java中有三种访问修饰符:public、protected和private。它们用于控制类、属性和方法的可见性和访问权限。

public: 公共的,可以被任何类访问;
protected:受保护的,可以被同一包内的类和该类的子类访问;
private:私有的,只能被该类的内部方法访问。

通过合理地使用访问修饰符,我们可以将类的实现细节隐藏起来,避免外部代码直接访问和修改对象的内部状态,从而提高了代码的安全性和稳定性。

此外,Java还提供了封装的另一种实现方式,即getter和setter方法。getter方法用于获取属性的值,setter方法用于设置属性的值。通过这种方式,我们可以控制属性的读写操作,同时可以在读写属性时添加一些额外的逻辑或验证。


1.1private实现封装

直接使用public

class Person {
	public String name = "张三";
	public int age = 18;
}
class Test {
	public static void main(String[] args) {
		Person person = new Person();
		System.out.println("我叫" + person.name + ", 今年" + person.age + "岁");
	}
}

执行结果
我叫张三, 今年18岁

  • 这样的代码导致类的使用者(main方法的代码)必须要了解 Person 类内部的实现, 才能够使用这个类. 学习成本较高
  • 一旦类的实现者修改了代码(例如把 name 改成 myName), 那么类的使用者就需要大规模的修改自己的代码, 维 护成本较高

范例: 使用 private 封装属性, 并提供 public 方法供类的调用者使用.

lass Person {
	private String name = "李四";
	private int age = 20;
	
	public void show() {
		System.out.println("我叫" + name + ", 今年" + age + "岁");
	}
}
class Test {
	public static void main(String[] args) {
		Person person = new Person();
		person.show();
	}
}

执行结果
我叫李四, 今年20岁

  • 此时字段已经使用 private 来修饰. 类的调用者(main方法中)不能直接使用. 而需要借助 show 方法. 此时类的使用者就不必了解 Person 类的实现细节.
  • 同时如果类的实现者修改了字段的名字, 类的调用者不需要做出任何修改(类的调用者根本访问不到name, age 这样的字段).

那么问题来了~~ 类的实现者万一修改了 public 方法 show 的名字, 岂不是类的调用者仍然需要大量修改代码嘛?
这件事情确实如此, 但是一般很少会发生. 一般类的设计都要求类提供的 public 方法能比较稳定, 不应该频繁发生大的改变. 尤其是对于一些基础库中的类, 更是如此. 每次接口的变动都要仔细考虑兼容性问题.


!

  • private 不光能修饰字段, 也能修饰方法
  • 通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public,就需要视具体情形而定. 一般我们希 望一个类只提供 “必要的” public 方法, 而不应该是把所有的方法都无脑设为 public.

1.2getter和setter方法

当我们使用 private 来修饰字段的时候, 就无法直接使用这个字段了。(详细可查看上面的访问修饰符修饰范围)

class Person {
	private String name = "张三";
	private int age = 18;
	
	public void show() {
		System.out.println("我叫" + name + ", 今年" + age + "岁");
	}
}
class Test {
	public static void main(String[] args) {
		Person person = new Person();
		person.age = 20;
		person.show();
	}
}

// 编译出错
//Test.java:13: 错误: age可以在Person中访问private
//	person.age = 20;
//		  ^
//1 个错误

此时如果需要获取或者修改这个 private 属性, 就需要使用 getter / setter 方法
代码示例:

class Person{
	private String name;//实例成员变量
	private int age;

	public void setName(String name){
	//name = name;//不能这样写 因为局部变量优先
	this.name = name;//this引用,表示调用该方法的对象
	}
	public String getName(){
		return name;
	}

	public void show(){
		System.out.println("name:" + name + "age:" + age);
	}
}
public static void main(String[] args){
	person person = new Person();
	person.setName("haoyang");
	String name = person.getName();
	System.out.println(name);
	person.show();
}

运行结果:
haoyang
name:haoyang age:0


!

  • getName即为getter方法,表示获取这个成员的值。
  • setName即为setter方法,表示设置这个成员的值。
  • 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this,相当与自赋值。this表示当前实例的引用。
  • 不是所用的字段都一定提供setter/getter方法,而是要根据实际情况决定提供那种方法。
  • 在IDEA中可以使用alt + insert(或者 alt + F12)快速生成 setter / getter 方法。在VSCode中可以使用鼠标右键 菜单-> 源代码操作 中自动生成setter / getter方法。

2.构造方法

构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作.
new 执行过程

  • 为对象分配内存空间
  • 调用对象的构造方法

2.1基本语法

语法规则

  • 方法名称必须与类名称相同
  • 构造方法没有返回值类型声明
  • 每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)
    !
  • 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数。
  • 若类中定义了构造方法,则默认的无参构造将不再生成。(救急不救穷)
  • 构造方法支持重载. 规则和普通方法的重载一致。
class Person {
	private String name;//实例成员变量
	private int age;
	private String sex;
	//默认构造函数 构造对象
	public Person() {
		this.name = "caocao";
		this.age = 10;
		this.sex = "男";
	}
	//带有3个参数的构造函数
	public Person(String name,int age,String sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
		}
	public void show(){
		System.out.println("name: "+name+" age: "+age+" sex: "+sex);
	}
}
public class Main{
	public static void main(String[] args) {
		Person p1 = new Person();//调用不带参数的构造函数 如果程序没有提供会调用不带参数的构造函数
		p1.show();
		Person p2 = new Person("zhangfei",80,"男");//调用带有3个参数的构造函数
		p2.show();
	}
}

执行结果
name: caocao age: 10 sex: 男
name: zhangfei age: 80 sex:男

2.2this关键字

this:表示当前对象引用(注意不是当前对象,因为使用this时对象还没生成). 可以借助 this 来访问对象的字段和方法。

class Person {
	private String name;//实例成员变量
	private int age;
	private String sex;
	//默认构造函数 构造对象
	public Person() {
		//this调用构造函数
		this("abc", 18, "max");//调用构造函数,必须放在第一行进行显示
	}
	//这两个构造函数之间的关系为重载。
	public Person(String name,int age,String sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	public void show() {
		System.out.println("name: "+name+" age: "+age+" sex: "+sex);
	}
}
public class Main{
	public static void main(String[] args) {
		Person person = new Person();//调用不带参数的构造函数
		person.show();
	}
}

输出结果:
name: abc age: 18 sex: max

可以发现在构造函数的内部,就可以使用this关键字,构造函数是用来构造对象的,对象还没有构造好,就已经使用了this,那this还代表当前对象吗?当然不是,this代表的是当前对象的引用.

3.代码块

字段的初始化方式有:

  1. 就地初始化
  2. 使用构造方法初始化
  3. 使用代码块初始化

前两种方式前面篇幅已经见过了, 接下来介绍第三种方式, 使用代码块初始化

3.1什么是代码块

使用 {} 定义的一段代码.
根据代码块定义的位置以及关键字,又可分为以下四种:

  • 普通代码块
  • 构造块
  • 静态块
  • 同步代码块

3.2普通代码块

普通代码块:定义在方法中的代码块

public class Main{
	public static void main(String[] args){
		{//直接使用{}定义,普通代码块
			int x = 1;
			System.out.println("x1 = " + x);
		}
		int x = 2;
		System.out.println("x2 = " + x);
	}
}

运行结果:
x1 = 1
x2 = 2

(这种用法较少见)

3.3构造代码块

构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量.

class Person{
    private String name;//实例成员变量
    private int age;
    private String sex;
    public Person() {
        System.out.println("I am Person init()!");
    }
    //实例代码块
    {
        this.name = "abc";
        this.age = 12;
        this.sex = "man";
        System.out.println("I am instance init()!");
    }
    public void show(){
        System.out.println("name: "+name+" age: "+age+" sex: "+sex);
    }
}
public class Main {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.show();
    }
}

运行结果:
I am instance init()!
I am Person init()!
name: abc age: 12 sex: man

!
(初学者)注意看运行结果的顺序和代码编写的顺序,
相信聪明的你一下子就发现了,实例代码块是优于构造函数执行的。
是的,代码块是优于构造函数执行的。

3.4静态代码块

使用static定义的代码块。一般用于初始化静态成员属性

class Person{
    private String name;//实例成员变量
    private int age;
    private String sex;
    private static int count = 0;//静态成员变量 由类共享数据 方法区
    public Person(){
        System.out.println("I am Person init()!");
    }
    //实例代码块
    {
        this.name = "abc";
        this.age = 12;
        this.sex = "man";
        System.out.println("I am instance init()!");
    }
    //静态代码块
    static {
        count = 10;//只能访问静态数据成员
        System.out.println("I am static init()!");
    }
    public void show(){
        System.out.println("name: "+name+" age: "+age+" sex: "+sex);
    }
}
public class Main {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();//静态代码块是否还会被执行?
    }
}

运行结果:
I am static init()!
I am instance init()!
I am Person init()!
Iam instance init()!
I am Person init()!

!

  • 静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
  • 静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行
  • 42
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值