面向对象程序有三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。
封装就像是把东西放在⼀个盒子里,并且控制谁可以打开这个盒子,以及如何使用盒子里的东西。在编程中,它指的是将数据(属性)和操作这些数据的方法(函数)包装在⼀个单元(通常是类)内。
如:对于电脑这样⼀个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB 插孔等,让用户来和计算机进行交互,完成日常事务。


对于计算机使用者而言,不用关心内部核心部件,如主板上线路是如何布局的,CPU内部是如何设 计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
代码实现:
class Student{
private String name; //使⽤private 修饰
private int age; //使⽤private 修饰
public void eat() {
System.out.println(this.name + " 正在吃饭!");
}
public void show() {
System.out.println("name: "+name+" 年龄:"+age);
}
}
public class Test {
public static void main(String[] args) {
Student stu= new Student();
}
}上述代码使用private修饰之后,在Test类中无法通过person引用来进行访问数据,这里封装就起到 了作用!
如果要想访问,此时只能手动提供get和set方法作为公开的接口来进行访问!
(还是Alt + Ins,选择单独提供get或set,或者是都提供)

代码实现:
class Student{
private String name; //使⽤private 修饰
private int age; //使⽤private 修饰
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 void eat() {
System.out.println(this.name + " 正在吃饭!");
}
public void show() {
System.out.println("name: "+name+" 年龄:"+age);
}
}
public class Test {
public static void main(String[] args) {
Student stu= new Student();
stu.setAge(10);
System.out.println(person.getAge());
}
}封装可以降低对象和对象之间的耦合度,当对象内部发生变化时,只需要修改对象内部即可,不会影响到外部程序,因为公开的接口是不会发生改变的
封装是隐藏了对象内部的实现细节,只提供了公开的接口给外部,使用起来更加简单
封装可以隐藏对象的具体实现细节,阻止外部程序直接访问对象的内部状态,从而保护数据不被意外修改或破坏
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在⼀起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

(1)public修饰的成员变量,在所指定情况下均是可以正常访问的
(2)private修饰的成员变量,只能在当前类中来使用
(3)default表示什么修饰符都不加,此时只能在包当中才能被访问
(4)protected的讲解我们在继承中去看
关键字static可以修饰成员变量和成员方法。
我们以Student类为例,假设有3个学生,他们都是在同⼀个教室上课,那么我们如何定义这个属性呢?如下这种方式定义可以吗?
class Student{
private String name;
private int age;
public String classRoom;
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
}
}答案当然是不可以,虽然从程序角度出发没有报错信息,但是从设计角度看,是有问题的!!!
之前在Student类中定义的成员变量,每个对象中都会包含⼀份(称之为实例变量),因为需要使用这些信息来描述具体的学生。而现在要表示学生上课的教室,这个教室的属性并不需要每个学生对象中都存储⼀份,而是需要让所有的学生来共享。在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
class Student{
private String name;
private int age;
public String classRoom = "1-101";
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
}
}static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
静态成员变量特性:
(1)不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
(2)既可以通过对象访问,也可以通过类名访问,但⼀般更推荐使用类名访问
(3)类变量存储在方法区当中
(4)生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
我们可以通过:类名.静态成员变量的方式进行访问
class Student{
private String name;
private int age;
public static String classRoom = "1-101";
}
public class Test {
public static void main(String[] args) {
// 静态成员变量可以直接通过类名访问
System.out.println(Student.classRoom);
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
// 也可以通过对象访问:但是classRoom是三个对象共享的
System.out.println(stu1.classRoom);
System.out.println(stu2.classRoom);
System.out.println(stu3.classRoom);
}
}(但是我们不建议使⽤对象的引用去访问静态成员变量)
Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员⼀般是通过静态方法来访问的。
public class Student{
private static String classRoom = "001";
public static String getClassRoom(){
return classRoom;
}
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.getClassRoom());
}
}静态方法特性:
(1)不属于某个具体的对象,是类方法
(2)可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者
(3)不能在静态方法中访问任何非静态成员变量
public static String getClassRoom(){
System.out.println(this.age);
return classRoom;
}
// 编译失败:Error:(35, 28) java: ⽆法从静态上下⽂中引⽤⾮静态 变量this
public static String getClassRoom(){
age += 1;
return classRoom;
}
// 编译失败:Error:(35, 9) java: ⽆法从静态上下⽂中引⽤⾮静态 变量age (4)静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用
public static String getClassRoom(){
doClass(); //该访问为⾮静态⽅法
return classRoom;
}
// 编译报错:Error:(35, 9) java: ⽆法从静态上下⽂中引⽤⾮静态 ⽅法doClass() #注:静态成员变量⼀般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性
静态成员变量的初始化分为两种:就地初始化和静态代码块初始化。
就地初始化指的是:在定义时直接给出初始值
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom = "1-101";
}那么什么是代码块呢?
使用{} 定义的⼀段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
(1)普通代码块
(2)构造代码块(有的书上叫实例代码块)
(3)静态代码块
(4)同步代码块(后续讲解多线程部分再谈)
普通代码块:定义在方法中的代码块.
public class Main{
public static void main(String[] args) {
{ //直接使⽤{}定义,普通⽅法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
// 执⾏结果
x1 = 10
x2 = 100构造代码块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块⼀般用于初始化实例成员变量。
public class Student{
//实例成员变量
private String name;
private String gender;
private int age;
private double score;
public Student() {
System.out.println("I am Student init()!");
}
//实例代码块
{
this.name = "xunxingtanlu";
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) {
Student stu = new Student();
stu.show();
}
}
// 运⾏结果
I am instance init()!
I am Student init()!
name: xunxingtanlu age: 12 sex: man使用static定义的代码块称为静态代码块。⼀般用于初始化静态成员变量。
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom;
//实例代码块
{
this.name = "寻星探路";
this.age = 12;
this.gender = "man";
System.out.println("I am instance init()!");
}
// 静态代码块
static {
classRoom = "001";
System.out.println("I am static init()!");
}
public Student(){
System.out.println("I am Student init()!");
}
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}#注:
(1)静态代码块不管生成多少个对象,其只会执⾏⼀次
(2)静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
(3)如果⼀个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
(4)实例代码块只有在创建对象时才会执行