Java - 类与对象2
静态变量和静态方法
Static
静态的内容,我们可以理解为是属于这个类的,也可以理解为是所有对象共享的内容。
我们通过使用 static 关键字来声明一个变量或一个方法为静态的,一旦被声明为静态,那么通过这个类创建的所有对象,操作的都是同一个目标,也就是说,对象再多,也只有这一个静态的变量或方法。
一个对象改变了静态变量的值,那么其他的对象读取的就是被改变的值。
一般情况下,我们并不会通过一个具体的对象去修改和使用静态属性,而是通过这个类去使用:
public class Person {
String name;
int age;
String sex;
static String info; //这里我们定义一个info静态变量
}
public static void main(String[] args) {
Person.info = "让我看看";
System.out.println(Person.info);
}
同样的,我们可以将方法标记为静态:
static void test(){
System.out.println("我是静态方法");
}
静态方法同样是属于类的,而不是具体的某个对象,所以说,就像下面这样:
因为静态方法属于类的,所以说我们在静态方法中,无法获取成员变量的值, 同样的,在静态方法中,无法使用this关键字,因为this关键字代表的是当前的对象本身。
但是静态方法是可以访问到静态变量的.
静态变量初始化
我们实际上是将 .class 文件丢给 JVM 去执行的,而每一个 .class 文件其实就是我们编写的一个类,我们在 Java 中使用一个类之前, JVM 并不会在一开始就去加载它,而是在需要时才会去加载(优化)一般遇到以下情况时才会会加载类:
- 访问类的静态变量,或者为静态变量赋值
- new 创建类的实例(隐式加载)
- 调用类的静态方法
- 子类初始化时
- 其他的情况会在讲到反射时介绍
所有被标记为静态的内容,会在类刚加载的时候就分配,而不是在对象创建的时候分配,所以说静态内容一定会在第一个对象初始化之前完成加载。
包的访问与控制
包的声明和导入
包其实就是用来区分类位置的东西,也可以用来将我们的类进行分类(类似于C++中的namespace)随着我们的程序不断变大,可能会创建各种各样的类,他们可能会做不同的事情,那么这些类如果都放在一起的话,有点混乱,我们可以通过包的形式将这些类进行分类存放。
包的命名规则同样是英文和数字的组合,最好是一个域名的格式,比如我们经常访问的 www.baidu.com ,后面的 baidu.com 就是域名,我们的包就可以命名为com.baidu,其中的.就是用于分割的,对应多个文件夹,比如com.test

我们之前都是直接创建的类,所以说没有包这个概念,但是现在,我们将类放到包中,就需要注意了:
需要通过关键字 package,用于指定当前类所处的包的,注意,所处的包和对应的目录是一一对应的。
package com.test;
//在放入包中,需要在类的最上面添加package关键字来指明当前类所处的包
public class Main {
//将Main类放到com.test这个包中
public static void main(String[] args) {
}
}
当我们使用同一个包中的类时,直接使用即可(之前就是直接使用的,因为都直接在一个缺省的包中)
而当我们需要使用其他包中的类时,需要先进行导入才可以:
需要通过关键字 import 导入我们需要使用的类,当然,只有在类不在同一个包下时才需要进行导入,如果一个包中有多个类,我们可以使用*表示导入这个包中全部的类:
import com.test.entity.Person;
//使用import关键字导入其他包中的类
import com.test.entity.*;
Java会默认导入java.lang这个包下的所有类,因此我们不需要手动指定。
不同类的重名问题
在不同包下的类,即使类名相同,也是不同的两个类:
package com.test.entity;
public class String {
//我们在自己的包中也建一个名为String的类
}
由于默认导入了系统自带的String类,并且也导入了我们自己定义的String类,那么此时就出现了歧义,编译器不知道到底我们想用的是哪一个String类,所以说我们需要明确指定:
public class Main {
public static void main(java.lang.String[] args) {
//主方法的String参数是java.lang包下的,我们需要明确指定一下,只需要在类名前面添加包名就行了
com.test.entity.String string = new com.test.entity.String();
}
}
我们只需要在类名前面把完整的包名也给写上,就可以表示这个是哪一个包里的类了,当然,如果没有出现歧义,默认情况下包名是可以省略的,可写可不写。
访问权限控制
Java中引入了访问权限控制(可见性),我们可以为成员变量、成员方法、静态变量、静态方法甚至是类指定访问权限,不同的访问权限,有着不同程度的访问限制:
- private - 私有,标记为私有的内容无法被除当前类以外的任何位置访问。
- 什么都不写 - 默认,默认情况下,只能被类本身和同包中的其他类访问。
- protected - 受保护,标记为受保护的内容可以能被类本身和同包中的其他类访问,也可以被子类访问(子类我们会在下一章介绍)
- public - 公共,标记为公共的内容,允许在任何地方被访问。
| 当前类 | 同一个包下的类 | 不同包下的子类 | 不同包下的类 | |
|---|---|---|---|---|
| public | ✅ | ✅ | ✅ | ✅ |
| protected | ✅ | ✅ | ✅ | ❌ |
| 默认 | ✅ | ✅ | ❌ | ❌ |
| private | ✅ | ❌ | ❌ | ❌ |
默认的情况下,在当前包以外的其他包中无法访问。
如果某个类中存在静态方法或是静态变量,那么我们可以通过静态导入的方式将其中的静态方法或是静态变量直接导入使用,但是同样需要有访问权限的情况下才可以:
public class Person {
String name;
int age;
String sex;
public static void test(){
System.out.println("我是静态方法!");
}
}
静态导入:
import static com.test.entity.Person.test; //静态导入test方法
public class Main {
public static void main(String[] args) {
test(); //直接使用就可以,就像在这个类定义的方法一样
}
}
