文章目录
- 6. 封装
- 6.1 封装的概念
- 6.2 访问限定符
- 6.3 封装拓展之包
- 6.3.1 包的概念
- 6.3.2 导入包中的类
- 6.3.3 自定义包
- 7. static成员
- 7.1 再谈学生类
- 7.2 static修饰成员变量
- 7.3 static修饰成员方法
- 7.4 static成员变量初始化
- 8. 代码块
- 8.1 代码块概念以及分类
- 8.2 普通代码块
- 8.3 构造代码块
- 8.4 静态代码块
- 10. 对象的打印
6. 封装
6.1 封装的概念
对于面向对象的语言来说 有几个比较重要的特征:封装、继承、多态。
这里有一个误区:这三个特征不是哪个语言的特征,而是面向对象的特征。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互.
6.2 访问限定符
访问权限用来控制方法或者字段能否直接在类外使用
No | 范围 | private | default | protected | public |
---|---|---|---|---|---|
1 | 同一个包的同一类 | √ | √ | √ | √ |
2 | 同一个包中的不同类 | √ | √ | √ | |
3 | 不同包中的子类 | √ | √ | ||
4 | 不同包中的非子类 | √ |
【说明:】
- protected主要是用在继承中
- default权限指:什么都不写时的默认权限
- 访问权限除了可以限定类中成员的可见性,也可以控制类的可见性。
class Student {
private String name;
private int age;
private String stuNum;
// get 和 set方法
//当成员变量被private修饰了之后 该成员变量只能在同一个包中的同一个类中被访问
// 提供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 getStuNum() {
return stuNum;
}
public void setStuNum(String stuNum) {
this.stuNum = stuNum;
}
//构造方法
public Student(String name, int age, String stuNum) {
this.name = name;
this.age = age;
this.stuNum = stuNum;
}
}
public static void main(String[] args) {
Student student = new Student("zhangsan", 11, "202320044118");
System.out.println(student.getName());// zhangsan
// System.out.println(student.name);//报错
}
6.3 封装拓展之包
6.3.1 包的概念
在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件下,也可以对某个文件夹下的音乐进行更详细的分类。
包的本质就是一个 文件夹 ,可以理解为包就是为了组织类的; 在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
6.3.2 导入包中的类
Java 中已经提供了很多现成的类供我们使用. 例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date类.
//导入一个包(方法1)
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
但是这种写法比较麻烦一些, 可以使用 import语句导入包.
import java.util.Date;
// 或者写成
// import java.util.*;
// 但是这种写法并不推荐
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
// util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
Date date = new Date();
System.out.println(date.getTime());
}
}
// 编译出错
Error:(5, 9) java: 对Date的引用不明确
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配
6.3.3 自定义包
鼠标放在src上右键—new—package
包名采用小驼峰的写法,一般采用公司名的倒写形式(比如:com.baidu.www)
建完包之后 如果包名是一行的话:
打开文件路径:
src: 程序的默认包,程序在运行的时候默认是在Src这个包下面找可执行程序,去执行。
7. static成员
7.1 再谈学生类
public class Student {
private String name;
private int age;
private String stuNum;
private String classRoom;
public Student(String name, int age, String stuNum, String classRoom) {
this.name = name;
this.age = age;
this.stuNum = stuNum;
this.classRoom = classRoom;
}
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 getStuNum() {
return stuNum;
}
public void setStuNum(String stuNum) {
this.stuNum = stuNum;
}
public String getClassRoom() {
return classRoom;
}
public void setClassRoom(String classRoom) {
this.classRoom = classRoom;
}
}
public class Test {
public static void main(String[] args) {
Student student1 =
new Student("zhansgan", 21, "551453666", "1103");
Student student2 =
new Student("lisi", 21, "1576632", "1103");
Student student3 =
new Student("wangwu", 21, "588556546565", "1103");
}
}
实例化三个学生对象student1, student2, student3。每个对象都有自己特有的姓名、年龄、学号等信息。
假如这三个同学都是一个班的,那么他们一定在同一个教室上课。
之前在Student类中定义的成员变量,每个对象中都会包含一份(称之为实例变量),因为需要使用这些信息来描述具体的学生。而现在要表示学生上课的教室,这个教室的属性并不需要每个学生对象中都存储一份,而是需要让所有的学生来共享。在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
7.2 static修饰成员变量
public class Student {
private String name;
private int age;
private String stuNum;
private static String classRoom;
//...
}
【静态成员变量特性】
- 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
- 既可以通过对象访问,也可以通过类名访问(合法但是不合理😉),但一般更推荐使用类名访问.
- 类变量存储在方法区当中,所有的对象共享。
- 静态成员变量的生命周期伴随类的一生,当类被加载的时候 静态成员变量就被加载了;类的卸载而销毁。
题目: 下面一段程序的输出结果是多少?
输出12
不管new多少个对象,从始至终只有一个count ,不管是通过哪一个对象访问的, 都是在对同一个count进行操作的。
7.3 static修饰成员方法
一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性如何在类外访问呢?
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.classRoom);
}
}
// 编译失败:
// Error:(10, 35) java: classRoom 在 extend01.Student 中是 private 访问控制
Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的。
public class Student{
// ...
private static String classRoom = "306";
// ...
public static String getClassRoom(){
return classRoom;
}
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.getClassRoom());
}
}
输出:306
【静态方法特性】
- 不属于某个具体的对象,是类方法
- 可以通过对象调用,也可以通过类名.静态方法名(…)方式调用,更推荐使用后者
- 不能在静态方法中访问任何非静态成员变量
public static String getClassRoom(){
System.out.println(this);
return classRoom;
}
// 编译失败:Error:(35, 28) java: 无法从静态上下文中引用非静态 变量 this
public static String getClassRoom(){
age += 1;
return classRoom;
}
// 编译失败:Error:(35, 9) java: 无法从静态上下文中引用非静态 变量 age
- 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用.
public static String getClassRoom(){
doClass();
return classRoom;
}
// 编译报错:Error:(35, 9) java: 无法从静态上下文中引用非静态 方法 doClass()
在静态方法中,是不能访问普通的非静态成员变量和方法的 普通的非静态成员变量是依赖于对象的 要通过对象的引用去访问 而静态的成员方法是通过类名调用的 所以在通过类名调用静态方法时,是传不了this的,this是当前对象的引用,传不了this,我们就不知道当前对象是什么都不知道。
除非我们在这个静态方法中new一个对象,通过这个对象的引用去访问。
所以在static的成员方法中,是不存在this的。
-
静态方法无法重写, 不能用来实现多态。 -
在普通的成员方法里面可以调用静态得成员变量和成员方法。
age是被static修饰的,所以age是不依赖于对象的,age不是在person对象里面的age,age是属于类的。
person=null;代表person是不指向于任何对象的。
为什么在一个方法内部不能定义一个静态的成员变量。
定义时,加上static就是类变量,定义在方法里面就是局部变量了,它挺有脾气的,它不同意。
7.4 static成员变量初始化
注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性.
静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。
1. 就地初始化
就地初始化指的是:在定义时直接给出初始值
public class Student {
private String name;
private int age;
private String stuNum;
private static String classRoom = "106";
//...
}
8. 代码块
8.1 代码块概念以及分类
使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块(不太能用的到)
- 非静态代码块(实例代码块/ 构造代码块)
- 静态代码块
- 同步代码块(后续线程部分)
8.2 普通代码块
普通代码块:定义在方法中的代码块.
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
这种用法较少见
8.3 构造代码块
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化类里面非静态的数据成员。构造代码块定义在类的里面,方法的外面。
public class Student {
private String name;
private int age;
private String stuNum;
private static String classRoom = "106";
//构造方法
public Student(String name, int age, String stuNum, String classRoom) {
this.name = name;
this.age = age;
this.stuNum = stuNum;
this.classRoom = classRoom;
System.out.println("构造方法被调用了....");
}
//构造代码块
{
this.age = 100;
System.out.println("构造代码块被调用了....");
}
}
public class Test {
public static void main(String[] args) {
Student student1 =
new Student("zhansgan", 21, "551453666", "1103");
}
}
输出结果:
构造代码块被调用了....
构造方法被调用了....
和定义顺序没有关系,一定是先执行构造代码块,再执行构造方法。
8.4 静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
public class Student {
private String name;
private int age;
private String stuNum;
private static String classRoom = "106";
public Student(String name, int age, String stuNum, String classRoom) {
this.name = name;
this.age = age;
this.stuNum = stuNum;
this.classRoom = classRoom;
System.out.println("构造方法被调用了....");
}
{
this.age = 100;
System.out.println("构造代码块被调用了....");
}
static {
classRoom = "415";
System.out.println("static{}......");
}
}
public static void main(String[] args) {
Student student1 =
new Student("zhansgan", 21, "551453666", "1103");
}
输出结果:
static{}......
构造代码块被调用了....
构造方法被调用了....
执行顺序和定义顺序无关,执行顺序:静态代码块—>实例代码块—>构造方法。
public static void main(String[] args) {
Student student1 =
new Student("zhansgan", 21, "551453666", "1103");
System.out.println("==============");
Student student2 =
new Student("lisi", 21, "1576632", "1103");
}
输出结果:
static{}......
构造代码块被调用了....
构造方法被调用了....
==============
构造代码块被调用了....
构造方法被调用了....
可以看到当我们实例化两个学生对象的时候,静态代码块只执行了一次。
注意事项:
- 静态代码块不管生成多少个对象,其只会执行一次
- 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
- 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
- 实例代码块只有在创建对象时才会执行
静态代码块初识化静态数据成员,非静态代码块初始化非静态数据成员。
静态代码块中不会出现this.
10. 对象的打印
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = 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("zhangsan", 20);
System.out.println(student);
}
}
输出结果:Student@3b07d329
归根结底,程序在最后调用了一个toString()