Java SE 是什么,包括哪些内容(十一)?
本文内容参考自Java8标准
前面博文中的内容完全体现了Java中面向对象思想,但是,Java毕竟是从C和C++中而来,肯定存在不用创建对象就能使用的代码环节,那么如何与必须创建对象的代码环节区分呢?就是通过static关键字。
再来回顾一下面向对象创建对象的内容:
- 首先需要根据实际情况创建类。
// 创建一个类
public class Person{
//创建一个变量name代表姓名。
private String name;
//...其他的变量。
//构造方法
public Person(){}
//...其他的构造方法
//创建一个方法eat():
public void eat(){
//方法体
}
//...其他的方法
}
- 利用类创建类对象,并给对象取一个易识别的引用名称(也叫标识符)。
// 创建Person类对象p,p就是这个对象的引用名称(标识符).
Person p = new Person();
- 利用引用名称(标识符)去调用变量或者是方法。
//修改变量
p.name = "James";
// 调用方法
p.eat()
之前所接触的Java面向对象代码编程中,无外乎以上三步。
如果Java所有的内容全部限定为以上三步,同时还必须创建对象,这样的话就过于受限了。
从前面的博文中我们知道了,一个类,只要是创建了一个对象,那么这个对象的引用名称是存储在堆栈上的,而实际的对象是存储在堆上的。并且每一个对象都含有相同的类变量以及方法。
那么static关键字有以下作用:
- 如果是修饰一个类(只能修饰内部类,不能修饰外部类):
// static修饰一个类,需要特别声明的是static只能修饰一个内部类,
//不能修饰一个外部类
//内部类和外部类的知识点请及时关注后期博文更新。
//外部类Person
public class Person{
//内部类Child
static class Child{}
}
static不能修饰外部类:
static修饰内部类有什么用呢?答案可以很肯定的告诉你:
没什么用!
唯一的区别在于创建对象时候的代码:
用了static修饰:
// static修饰内部类
public class Person{
//内部类Child
static class Child{
//内部类构造方法(内部类其实就是一个普通的类,只不过是写在了另一个类的内部而已)
Child(){
System.out.print("我是一个内部类!");
}
}
//程序执行方法入口main方法
public static void main(String[] args){
//创建内部类Child的对象
new Person.Child();
}
}
用static修饰的内部类是可以直接用"外部类名称.内部类名称表示",因为这个内部类属于的是类,不属于对象,所以创建的形式就是"new 外部类名称.内部类名称()",也就是new Person.Child();
实际示例:
没用static修饰:
// static修饰内部类
public class Person{
//内部类Child
class Child{
//内部类构造方法(内部类其实就是一个普通的类,只不过是写在了另一个类的内部而已)
Child(){
System.out.print("我是一个内部类!");
}
}
//程序执行方法入口main方法
public static void main(String[] args){
//创建内部类Child的对象
new Person.new Child();
}
}
如果内部类没有被static修饰,就不属于类了,属于的是对象,所以需要先创建外部类的对象,再用外部类的对象去创建内部类的对象:
首先是Person p = new Person();
再p.new Child();
简写就是:new Person().new Child();
实际示例:
一般很少看到用static去修饰内部类,当然,如果这么写也没什么问题。
- static修饰变量:
用static修饰了的变量和没用static修饰的变量区别很大。
如果一个变量用了static修饰,无论你创建多少个对象,这个变量始终只有一 个!
如果一个变量没有用static修饰,那么创建了多少个对象,这个变量就会有多少个。
代码示例:
// static修饰变量
//类Person
public class Person{
//变量name,代表姓名
private String name;
//变量total,代表总数,用static修饰
private static int total;
//构造方法
public Person(){
//每次创建对象的时候total都自增1;
total++;
}
//程序执行的入口main方法
public static void main(String[] args){
new Person();
new Person();
new Person();
System.out.println(total);
}
}
实际结果示例(有static修饰):
实际结果示例(无static修饰):直接报错!因为没有与具体的对象关联。
所以,如果你需要控制某一个变量的存储区域只有一个(与创建对象的数量无关),就可以用static关键字修饰它!
- static修饰方法:
为什么会出现需要static修饰的方法?因为在一种极端的情况下,你调用方法的时候,不一定需要创建对象。我不知道使用"极端"修饰这种情况是否合适,不过严格来说,这确实是一种很特殊的情况。是什么情况呢?
工具类!
如果你正在创建的是一种工具类,它的方法全部都和工具有关,那么你在使用它的方法的时候,就不用创建它的对象,而是直接使用方法就行了。那么对应到代码里面是什么情况呢?
我们来看一个最经典的工具类的代码:
这个类就是:
System
源码:
变量全是static的:
方法全是static的:
我想如果你接触了Java,你应该从来没有见过:
System s = new System()
吧。你见过的应该都是
System.out…/System.err…
所以可以得出如下的结论:
static修饰的方法可以直接使用"类名称.方法名称()"这种形式调用,而不用创建类对象,再用对象标识符调用。方便简洁。
所以static修饰一个方法仅仅是简化了方法的调用形式,而并没有对方法的功能产生影响。方法仍然是一个普通方法,一旦被调用,方法体可以正常执行。
- static修饰代码块: Java中有一种形式的执行优先级最高:代码块 代码块分两种,首先来看一下用static修饰了的代码块:静态代码块。代码示例:
- 只要产生了对这个类的任何一个部分的调用,都首先执行静态代码块,再执行对应调用的内容,所以静态代码块具有最高的优先级,你可以将需要最先执行的代码,比如某些基础工作,放进代码块中,但是有一点需要注意:代码块里的内容只会执行一次!!! 再来看一下没有static修饰的代码块:代码块的优先级确实要高于构造方法:
这个是普通代码块,也需要注意,普通代码块也是只会执行一次的。 那么静态代码块和普通代码块的执行优先级如何呢?代码示例:
从结果可以看出,静态代码块的优先级要高于普通代码块!