零基础 “入坑” Java--- 九、类和对象(二)
文章目录
- 一、封装
- 1.何为封装
- 2.初识封装
- 3.封装之包
- 3.1 导入包中的类
- 3.2 再谈访问修饰限定符
- 二、深入static
- 三、代码块
- 1.普通代码块
- 2.构造代码块
- 3.静态代码块
- 四、对象的打印
面向对象有三大基本思想:封装、继承、多态。 在类和对象阶段,我们先来了解一下封装。
一、封装
1.何为封装
封装即:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口用来和对象进行交互。
对于这段晦涩难懂的解释,我们举个例子来说明一下:在我们使用电脑主机时,我们只需插入U盘即可读取U盘内容,但是在主机内部,却需要经过一系列很复杂的操作。我们可以将封装简单理解为:套壳屏蔽细节。
2.初识封装
我们先来定义一个学生类:
class Student {public String name; //姓名public int age; //年龄public void show() {System.out.println("姓名:" + this.name + " 年龄:" + this.age);}
}
public class Test {public static void main(String[] args) {Student student = new Student();student.name = "小王";student.age = 20;student.show();}
}
此时这个类中有两个被 public 修饰的成员变量,一个成员方法,代码可以正常运行。
但是当我们将成员变量的修饰符换为 private 时,main方法中的name和age就都变红了(如下图),此时再次运行,程序就会报错。这是因为:被private修饰之后,代表此变量只能在当前类中使用。
此时,name和age就相当于已经被我们封装上了,当我们想在类外使用name和age时,就需要使用Getter和Setter:
我们在空行单击鼠标右键,选择生成,再选择Getter和Setter,根据需要选择并生成方法,当我们在类外需要使用被封装的变量时,就可以调用生成的方法:
class Student {private String name; //姓名private int age; //年龄public void show() {System.out.println("姓名:" + this.name + " 年龄:" + this.age);}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 Test {public static void main(String[] args) {Student student = new Student();//调用生成的方法student.setName("小王");student.setAge(20);student.show();}
}
在类中,一般情况下我们将成员变量设置为private,成员方法设置为public。
对于访问修饰限定符一共有四种:public我们可以广泛使用,private我们只能在当前类中使用;而对于剩下的两个,我们先来了解一下包是什么。
3.封装之包
在Java中,包是对类、接口等封装机制的体现,是一种对类或者接口等很好的组织方式。 包还有一个作用:在同一个工程中允许存在相同名称的类,只要在不同的包中即可。
3.1 导入包中的类
Java中提供了很多现成的类供我们使用,如:
import java.util.Arrays;
import java.util.Scanner;
public class Test {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int[] array = {1,2,3,4,5};System.out.println(Arrays.toString(array));}
}
但并不建议采用简写的方式,可能会导致冲突情况的产生。
import java.util.*;
import java.sql.*;
public class Test {public static void main(String[] args) {Date date = new Date();}
}
这段代码不能正常运行,是因为util和sql中都存在Date类,这会导致歧义,编译出错。这种情况下,就需要使用完整的类名:
import java.util.*;
import java.sql.*;
public class Test {public static void main(String[] args) {//完整书写格式:java.util.Date date = new java.util.Date();}
}
此时代码可以正常运行。
我们还可以使用 import static 导入包中的静态方法和变量,对于这一点了解即可,使用很少。
3.2 再谈访问修饰限定符
学习完包,我们再来理解这个图片:default即默认权限,当不写访问修饰限定符时,都是默认为default。default因为其访问范围特点,也叫包访问权限。(何为protected我们以后再介绍。)
封装小结:
1.何为封装:对类中的成员通过private关键字进行隐藏,只对类外提供公开的接口(如Getter和Setter)。
2.封装的意义:隐藏类的实现细节,提高安全性。
二、深入static
class Student {private String name; //姓名private int age; //年龄public Student(String name, int age) {this.name = name;this.age = age;}public int classroom; //班级
}
public class Test {public static void main(String[] args) {Student s1 = new Student("小王", 18);s1.classroom = 310;Student s2 = new Student("小李", 17);s2.classroom = 310;Student s3 = new Student("小刘", 19);s3.classroom = 310;}
}
我们依旧使用学生类举例:先定义一个学生类,再实例化三个对象,依次为这三名学生的班级进行赋值,将他们分配到一个班级:
既然三名学生在一个班级,那么我们对代码进行修改:
class Student {private String name; //姓名private int age; //年龄public Student(String name, int age) {this.name = name;this.age = age;}public static int classroom; //班级
}
public class Test {public static void main(String[] args) {Student s1 = new Student("小王", 18);Student s2 = new Student("小李", 17);Student s3 = new Student("小刘", 19);Student.classroom = 310;}
}
在Java中,被static修饰的成员,称为静态成员或者类成员,其不属于某个具体的对象,是所有对象所共有的。 既可以通过对象访问,也可以通过类名访问,但推荐使用类名访问。
静态成员变量存储在方法区中,其生命周期伴随类(随类的加载而创建,随类的结束而销毁)。
静态成员不能直接调用非静态成员,所以在静态方法中不能使用this,但是可以通过对象的引用间接调用:
class Student {private String name; //姓名public void show() {System.out.println("嘻嘻");}public static void test() {System.out.println("哈哈");//通过对象的引用调用 √Student student = new Student();student.name = "小王";student.show();//直接调用 ×//name = "小王";//show();}
}
在学习构造方法时我们知道:构造方法的作用就是对 对象中的成员变量进行初始化;但是,静态成员变量一般不会放在构造方法中进行初始化。
静态成员变量的初始化有两种方式:就地初始化 和 静态代码块初始化。
就地初始化即:在定义时直接设定初始值:
class Student {public static int classroom = 310; //班级
}
静态代码块初始化:什么是代码块呢???
三、代码块
使用"{}"定义的一段代码称为代码块。 代码块又可分为:普通代码块、构造代码块、静态代码块、同步代码块(先不学)。
1.普通代码块
普通代码块即:定义在方法中的代码块:
public static void main(String[] args) {//普通代码块{int x = 10;System.out.println(x);}//代码块内的变量不能在代码块外使用System.out.println(x);}
2.构造代码块
构造代码块即:定义在类中的代码块(无访问修饰限定符)。也叫:实例代码块。构造代码块常用于初始化实例成员变量(非静态成员变量)。
class Student {public String name;public int age;//构造代码块{this.name = "小王";this.age = 20;System.out.println("构造代码块");}//无参构造方法public Student() {System.out.println("无参构造方法");}public void show() {System.out.println("姓名:" + this.name + " 年龄:" + this.age);}
}
public class Test_dmk {public static void main(String[] args) {Student student = new Student();student.show();}
}
运行结果为:
由此可得出:构造代码块先于构造方法执行。
3.静态代码块
使用static定义的代码块称为静态代码块,常用于初始化静态成员变量:
class Student {public String name;public int age;public static int classroom;//构造代码块{this.name = "小王";this.age = 20;System.out.println("构造代码块");}//静态代码块static {classroom = 310;System.out.println("静态代码块");}//无参构造方法public Student() {System.out.println("无参构造方法");}public void show() {System.out.println("姓名:" + this.name + " 年龄:" + this.age);}
}
public class Test_dmk {public static void main(String[] args) {Student student = new Student();student.show();}
}
运行结果为:
由此可得出:静态代码块先于构造代码块,先于构造方法执行。
但是当我们实例化两个对象时,会发现"静态代码块"只输出了一次。
我们总结一下:
1.无论实例化多少对象,静态代码块都只会执行一次。
2.静态成员变量是类的属性,在类加载时就会为其开辟空间并初始化(静态代码块在类加载时就会执行)。
3.当一个类中有多个静态代码块,编译器会根据静态代码块的顺序依次执行。
4.构造代码块只有在实例化对象时才会执行(通过new关键字实例化对象)。
四、对象的打印
在静态代码块的例子中,我们使用自己写的show方法打印成员变量。在Java中,有一个便捷的方法可以帮助我们完成这个任务,就是重写toString方法:
我们在空行单击鼠标右键,选择生成,再选择toString,选择需要显示的成员变量,就会生成如下图的方法:
当我们没有重写toString方法时,因为student是引用类型,所以存储的值为地址:
Student student = new Student();System.out.println(student);
但当我们重写toString方法后,再次运行这段代码,打印的结果就是toString方法中返回值的形式。
Ending。