摘要:
在理解静态类和非静态类的区别之前,先了解static
关键字的含义,static
修饰的变量称为类变量,static
修饰的方法称为类方法,类变量的特点:不同的对象共享同一个类变量,类方法的特点:加载字节码文件时分配入口地址,因此会有如下的定义:
- 类方法内不允许调用实例方法
- 类方法内不允许调用实例变量
- 可以通过类名直接调用类方法
- 可以通过实例对象调用类方法
如果你现在还不能都明白上面定义的含义,没有关系,接下来钊林会提供demo的方式深入分析static
关键字的使用,进而深入理解静态类和非静态类直接的区别。
一、类变量和实例变量的区别
static
修饰的变量被称为类变量,不使用static
修饰的变量称为实例变量,实例变量的特点:不同对象的实例变量被分配不同的内存,为了更好说明类变量和实例变量的区别,下面先举一个例子:demo打印公司所在地址信息
demo目录结构:
public class PrintAddress {
static String DEFAULT_ADDRESS="广东省广州市天河区创意软件园";
String currentAddress;
public PrintAddress(String currentAddress) {
this.currentAddress = currentAddress;
}
public void print(){
System.out.println(currentAddress);
}
public static void defaultPrint(){
System.out.println("默认公司地址:"+DEFAULT_ADDRESS);
}
}
创建两个PrintAddress
对象:addressA
和addressB
,创建对象时传入一个地址,代码如下:
public class DemoTestDrive {
public static void main(String[] args) {
PrintAddress addressA=new PrintAddress("当前公司A地址:"+"广州天河北路");
PrintAddress addressB=new PrintAddress("当前公司B地址:"+"广州越秀区");
addressA.print();
addressB.print();
addressA.defaultPrint();
addressB.defaultPrint();
}
}
运行demo,打印结果:
分析:
(1)创建PrintAddress
对象时,给实例变量currentAddress
赋值,两个对象的两个实例变量分别打印自己赋值的内容,说明不同对象的实例变量被分配不同的内存空间
为了说明类变量分配相同的内存,先打印默认类变量的值,然后改变默认类变量的值,再打印类变量,代码如下:
public class DemoTestDrive {
public static void main(String[] args) {
PrintAddress addressA=new PrintAddress("当前公司A地址:"+"广州天河北路");
PrintAddress addressB=new PrintAddress("当前公司B地址:"+"广州越秀区");
addressA.print();
addressB.DEFAULT_ADDRESS="广东省广州市华夏路10富力中心";
addressA.defaultPrint();
addressB.print();
addressB.defaultPrint();
}
}
运行demo,打印结果:
分析:
(1)类变量被分配相同的一处内存,改变其中一个对象的类变量,其它对象的类变量也会改变,不同对象的类变量共享同一处内存。
类变量和实例变量的区别:
(1)类变量共享同一处内存
(2)实例变量被分配不同的内存
实例应用:
改变类变量的值,所有引用到该类变量的地方会受到影响,为了记录用户的登录状态,在用户类UserInfo
声明了一个类变量loginState
,记录登录或退出的状态,在所有需要使用登录功能的地方,通过检测loginState
属于false或true,识别是否登录。
当用户点击了注销,程序改变loginState
的状态为false,所有使用loginState
的地方同时检测到false,即退出登录。
二、类方法和实例方法的区别
static
修饰的方法称为类方法,没有使用static
修饰的方法被称为实例方法,实例方法的特点:创建对象后,类中的实例方法分配入口地址,通过对象调用实例方法;类方法的特点:类的字节码加载到内存时分配入口地址,可以通过类名调用类方法。
为什么类方法不能调用实例变量、实例方法?
分析:明白了类方法和实例方法的特点后,你会很清楚将字节码加载到内存时,类方法就分配了入口地址,但因为没有通过new
关键字创建对象,故实例变量还没有分配内存,同时实例方法也没有分配入口地址,这个时候通过类方法调用实例变量、实例方法会报错。
在前面的例子:打印公司所在地址信息,可以改成通过类名调用类方法defaultPrint()
或类变量DEFAULT_ADDRESS
,代码如下:
public class DemoTestDrive {
public static void main(String[] args) {
PrintAddress addressA=new PrintAddress("当前公司A地址:"+"广州天河北路");
PrintAddress addressB=new PrintAddress("当前公司B地址:"+"广州越秀区");
addressA.print();
PrintAddress.DEFAULT_ADDRESS="广东省广州市华夏路10富力中心";
PrintAddress.defaultPrint();
addressB.print();
PrintAddress.defaultPrint();
}
}
运行demo,打印结果:
实例应用:
如果一个方法不需要操作实例成员就可以实现某种功能,就可以考虑将这样的方法声明为类方法。这样做的好处是避免创建对象浪费内存。
三、静态类和非静态类的区别
static
关键字修饰的类称为静态类,不使用static
修饰的类被称为非静态类。总结前面static
修饰变量、方法的特点:(1)修饰变量,表明该变量被分配相同的内存空间,(2)修饰方法,表明该方法在类的字节码加载到内存时分配入口地址
静态类更准确的地说应该是静态嵌套类,静态嵌套类的特点:
(1)原本可以独立存在的类,却要借助外部类的壳来隐藏自己
(2)静态嵌套类不能直接引用外部类实例变量或实例方法
(3)静态嵌套类可以通过外部类的类名访问
在前面的例子:打印公司的地址,添加一个Builder
的静态嵌套类,通过该例子演示上述三个特点
public class PrintAddress {
static String DEFAULT_ADDRESS="广东省广州市天河区创意软件园";
String currentAddress;
public PrintAddress(String currentAddress) {
this.currentAddress = currentAddress;
}
public void print(){
System.out.println("当前公司地址:"+currentAddress);
}
public static void defaultPrint(){
System.out.println("默认公司地址:"+DEFAULT_ADDRESS);
}
/**
* 静态嵌套类(Static Nested Class)
* @author Administrator
*
*/
public static class Builder{
public Builder setCurrentAddress(String address) {
this.address = address;
return this;
}
public PrintAddress build(){
return new PrintAddress(address);
}
public static void about(){
System.out.println("I'm a static nested class!");
}
private String address;
}
/**
* 内部类(Inner Class)
*/
public class Company{
String companyName;
public Company(String companyName) {
this.companyName = companyName;
}
public String getCompanyName(){
return companyName;
}
public void print(){
System.out.println(currentAddress);
}
}
}
特点一演示:静态嵌套类Builder
可以独立于PrintAddress
而存在,另外一种写法,将Builder
独立成一个类,如下图:
特点二演示:静态嵌套类Builder
,如果想要访问外部类的实例变量currentAddress
或实例方法print()
,将会报错,如下图:
但是,内部类可以访问外部类的实例变量currentAddress
或实例方法print()
,如下图:
特点三演示:类似于类方法一样,静态嵌套类作为外部类的一部分,通过外部类类名访问静态嵌套类,获取静态嵌套类的实例,代码如下:
PrintAddress.Builder builder=new PrintAddress.Builder();
builder.setCurrentAddress("当前公司地址:"+"广东省越秀区北京路");
调用静态嵌套类的静态方法,代码如下:
PrintAddress.Builder.about();
类似于实例方法一样,获取内部类的实例,首先需要创建外部类的对象,通过对象调用内部类,代码如下:
PrintAddress printAddress=new PrintAddress("当前公司地址:"+"广东省越秀区北京路");
PrintAddress.Company company=printAddress.new Company("人力资源公司");
company.getCompanyName();
内部类的特点:不允许在内部定义静态的成员,否则报错
比如,如果开发者在内部类Company
定义了静态方法about()
,提示出错,如下图:
总结:静态嵌套类无法访问外部类的实例变量、实例方法,但可以访问外部类的类变量、类方法;内部类可以访问外部类的实例变量、实例方法,但不允许定义额外的静态变量、静态方法;静态嵌套类和内部类实例化的方式区别如下:
静态嵌套类实例化:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
内部类实例化:
OuterClass outerClass=new OuterClass();
OuterClass.InnerClass innerClass=outerClass.new InnerClass();
参考资料:http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
你可能感兴趣的文章
转载请注明出处: https://www.teachcourse.cn/2454.html ,谢谢支持!