对static的印象一直都是一句话:当加上该属性后,类不可被继承,方法不可被覆盖,属性不可被修改。然而却没有怎么实战过,这次通过一些代码上的优化发现了static的作用和小技巧,也加深了对它的理解。
1.static关键字修饰成员方法
class Team{
public Team(String msg) {
System.out.println(msg);
}
}
public class Person {
Team team1 = new Team("team1成员变量初始化");
static Team team2 = new Team("static成员team2成员变量初始化");
public Person(String msg) {
System.out.println(msg);
}
Team team3 = new Team("team3成员变量初始化");
static Team team4 = new Team("static成员team4成员变量初始化");
public static void funStatic() {
System.out.println("static修饰的funStatic方法");
}
public static void main(String[] args) {
Person p1 = new Person("p1初始化");
}
static成员team2成员变量初始化
static成员team4成员变量初始化
static修饰的funStatic方法
team1成员变量初始化
team3成员变量初始化
p1初始化
}
当大家执行后可能会发现一个问题,Java代码难道不是逐行执行的吗?呵呵,这就是static关键字的作用了。相比于修饰成员属性,修饰成员方法对于数据的存储上面并没有多大的变化,因为我们从上面可以看出,方法本来就是存放在类的定义当中的。可以使用"类名.方法名"的方式操作方法,避免了先要new出对象的繁琐和资源消耗。但是对于入行不久的小白lz来说,这个所谓的资源消耗还不是特别理解。
至于为什么使用"类名.方法名"的方式来操作方法,其实就相当于定义了一个全局的函数(只要导入该类所在的包即可)。不过它也有使用的局限,一个static修饰的类中,不能使用非static修饰的成员变量和方法,这很好理解,因为static修饰的方法是属于类的,如果去直接使用对象的成员变量,它会不知所措(不知该使用哪一个对象的属性)。
2.static静态块
我的理解是,在static静态块中的代码,在加载类的时候就首先执行。比如这样一个场景,不在数据库建表,但是需要保存一些自定义的状态,这个时候就可以采用static静态块,每次调用该类时,会先加载静态块,静态块会去读取你的json文件或者其他的文件,将之加载到内存中便于你的调用。
实际上,static修饰的成员的初始化可以更早的进行static修饰的类成员,在程序运行过程中,只需要初始化一次即可,不会进行多次的初始化。
private static Map<String,String> sba;
private static Map<String,String> abs;
private static Map<String,String> notify;
static {
try {
List<Map<String,String>> list = new ArrayList<>();
List<Map<String,String>> notifylist = new ArrayList<>();
File jsonFile = ResourceUtils.getFile("classpath:city.json");
String jsonSting = FileUtils.readFileToString(jsonFile);
JSONObject json = JSONObject.parseObject(jsonSting);
//1,加载供应商
JSONArray arrayCity = JSONArray.parseArray(json.getString("cityCode"));
for (int i=0;i<arrayCity.size();i++){
Map<String,String> maps = new TreeMap<>();
JSONObject jsonCity = JSONObject.parseObject(arrayCity.get(i).toString());
maps.put("apiBizCode",jsonCity.getString("apiBizCode"));
maps.put("supplierBizCode",jsonCity.getString("supplierBizCode"));
maps.put("supplierCode",jsonCity.getString("supplierCode"));
list.add(maps);
}
//建立 供应商编码 供应商业务 和api业务关系
sba = new HashMap<>();
//建议 编码供 编码 和供应商编码关系
abs = new HashMap<>();
//建议 供应商状态 供应商编码 和api编码关系
notify = new HashMap<>();
for(int i=0;i<list.size(); i++){
Map<String,String> temp = list.get(i);
String apiBizCode = temp.get("apiBizCode");
String supplierBizCode = temp.get("supplierBizCode");
String supplierCode = temp.get("supplierCode");
sba.put(supplierCode+"_"+supplierBizCode,apiBizCode);
abs.put(supplierCode+"_"+apiBizCode,supplierBizCode);
}
//2,加载回调订单状态
JSONArray arrayStauts = JSONArray.parseArray(json.getString("notifyStatus"));
for (int i=0;i<arrayStauts.size();i++){
Map<String,String> maps = new TreeMap<>();
JSONObject jsonCity = JSONObject.parseObject(arrayStauts.get(i).toString());
maps.put("apiNotifyStatus",jsonCity.getString("apiNotifyStatus"));
maps.put("supplierNotifyStatus",jsonCity.getString("supplierNotifyStatus"));
maps.put("supplierCode",jsonCity.getString("supplierCode"));
notifylist.add(maps);
}
for(int i=0;i<notifylist.size(); i++){
Map<String,String> temp = notifylist.get(i);
String apiNotifyStatus = temp.get("apiNotifyStatus");
String supplierNotifyStatus = temp.get("supplierNotifyStatus");
String supplierCode = temp.get("supplierCode");
//拿到api状态下的供应商编码和状态
notify.put(supplierCode+"_"+supplierNotifyStatus,apiNotifyStatus);
}
}catch (Exception e){
e.printStackTrace();
}
}
上面的代码是去读取相应的json文件,然后解析封装到相应的map数组中,再定义相应的方法进行调用即可。这种方式也是可以减轻内存消耗,毕竟对数据库的依赖降低了一点。
3.static静态导包
一句话定义,在一个类中定义了一个static关键字修饰的静态方法,在另外一个类中直接调用这个方法(不用类名.方法名的形式),那么它会在导入相应包的路径前加入相应的static选项。感觉这个用的不多,稍微提及一下。
4.对于static关键字的一些问题
4.1是否可以从一个static方法内部发出对非static方法的调用?
答案是不可以,既然static静态代码块是类加载即执行,那么它极有可能还没有创建任何的实例对象,如果调用非static方法,那么非static方法的对象关联到哪个上面呢?所以这样做是不可行的。
4.2static关键字是否可以大规模应用?
我觉得是因程序而异,就像在static代码块中就不能使用this,super这些关键字,并且在单例模式中运用static,有大概率会出现线程锁的现象,所以要仔细考虑应用。
总结一下开始说的那一句话:
被static修饰:
类不可被继承:通常是不可以直接用static修饰类名,只能说用static修饰匿名内部类然后进行调用,至于是否可以继承的问题,
我理解的是可以,但是要看定义的位置。
方法不可被覆盖:你可以定义一个static修饰的方法名,就算另外起一个这个方法名的方法也是可以的,因为修饰类型不同。
public static void amdintst() {
}
public void amdmintst() {
}
属性不可被修改:就算在子类中调用了父类的方法,子类不管怎么做修改父类都不会因此而产生任何改变。