static关键字:可以修饰成员、方法、代码块、静态内部类、静态导包。
1、修饰成员、方法、代码块,我们可以联想到它们在类初始化是的执行顺序,这里也可以把main主函数、构造函数、非静态代码块放在一起进行测试。
主函数的输出语句在实例化对象之前:静态代码块>静态方法/静态变量(这取决于在类中定义的顺序)>主函数输出>非静态代码块>构造函数。
demo测试:
public class String02 {
private static int i = 3;
private static int name(int i) {
return String02.i+i;
}
static {
System.out.println("静态代码块:"+name(6));
}
String02() {
System.out.println("构造方法:"+name(4));
}
{
System.out.println("非静态代码块:"+name(5));
}
public static void main(String[] args) {
System.out.println("静态方法:"+String02.name(1));
System.out.println("主函数运行");
new String02();
}
}
测试结果:
静态代码块:9
静态方法:4
主函数运行
非静态代码块:8
构造方法:7
总结:静态代码块会随着类的加载而执行,而且只会执行一次。所以会率先执行静态代码块(如果该类继承了某类,并且所继承的类中也有静态代码块,会先执行父类的静态代码块,再执行子类的静态代码块),紧接着运行main方法,实例化对象,首先执行非静态方法,然后是构造函数。
静态属性:所有对象共享,直接使用类名调用
生命周期:
创建:当类的字节码文件(.class)加载到方法区时,会扫描此方法中所有的静态属性,存放在静态常量区里。
销毁:项目结束时
优先级别:静态代码块优先于代码块
其实在这还会延伸出一个问题,就是为什么main方法会是static的?
执行一个java程序的时候,因为java都是以类作为程序的组织单元,当我们要执行的时候,jvm并不知道这个main方法会放到哪个类当中,也不知道是否是要产生类的一个对象,为了解决程序的运行问题,所以将这个main方法定义为static。
2、静态内部类
静态内部类就是在内部类的基础上加上static关键字,静态内部类和普通内部类还是有区别的:
1)、静态内部类只能访问外部类的静态变量和静态方法,而普通内部类可以访问外部类的所有成员和方法;
2)、首先静态内部类不依赖外部类,直接就可以创建,即OutClass.InClass inCl = new OutClass.InClass(); 的方式就可以创建,而普通内部类需要先创建外部类的实例对象,通过外部类的实例对象创建,即 OutClass ou = new OutClass(); OutClass.InClass inCl = ou.new InClass();
3)、外部类访问内部类的成员时,通过内部类的引用间接的访问,而静态内部类直接通过类名. 的方式访问,因为静态内部类是属于类的。
内部类的使用,因为Java是单继承的,我们可以通过内部类的形式来间接的实现“多继承”(每个内部类都能独立地继承一个接口或者类,而无论外部类是否已经继承了某个接口或者类。因此,内部类使多重继承的解决方案变得更加完整),假设外部类继承A类,内部类继承B类,可以调用B类的某个方法,再方便外部类使用。
demo测试:
public class String02 {
public void name02() {
System.out.println("我是String02的name()方法");
}
}
public class String03 {
public void name03() {
System.out.println("我是String03的name()方法");
}
}
public class String04 extends String02{
//静态内部类
public static class S extends String03{}
public static void main(String[] args) {
String04.S s1 = new String04.S();
s1.name03();
}
}
输出结果:我是String03的name()方法
//总结:这样我们就可以在外部类String04不继承String03这个类的前提下,调用String043中的方法了。
这里就会延伸出一个问题,我们已知一个内部类的实例对象(OutClass.InClass in = new OutClass.InClass(); ),再不通过实例对象.成员方法(in.name())的方式来使用内部类的name()方法呢?这里就会涉及的Java反射的一些问题,class对象中method的反射,首先获取class对象,然后通过class对象获取Method对象,其次通过method对象的invoke()方法来操作指定类中的成员方法。
3.1)、获取class对象,三种方式
Class.forName(“类的全限定名,包含包名”)
类的实例对象.getClass()
类名.class (ClassA.class)
3.2)、method的反射应用
我们获取到class对象只够就可以得到该对象里面的信息了,包括成员方法、成员变量、构造函数等信息,这里我们获取成员方法,通过class对象中方法的反射来操作指定类的成员方法。在java.lang.reflec.Method中封装了对成员函数的信息,Method对象可以通过两种方式获取,getMethods()、getDeclaredMethods() ,前者获取的是所有public修饰的方法,包含继承父类的,后者获取的是自身声明的方法,包括私有的(private、protected、默认以及public)的方法,但不包含继承的方法。
我们通过方法的名称和参数列表可以唯一确定一个方法,getMethod(String name, Class<?>… parameterTypes);name——方法名,parameterTypes——参数列表,它的传入方式有两种方式,假设方法有两个string的形参,则String.class, String.class,若参数是一个String数组,则String[].class;如果没有形参的话,则参数列表为空。
3.3)、invoke(Object obj, Object… args);
第一个是Object类型,也就是调用该方法的对象,第二个参数是一个可变参数类型,若方法的形参是一个string数组,则需要转换成object类型,(Object)String[]。
demo测试,这里只是简单做了个输出。
public class String04 extends String02{
//非静态内部类
public class S{
public void print(String [] sys) {
for (int i = 0; i < sys.length; i++) {
System.out.println(sys[i]);
}
}
}
//非静态内部类
public static class S1{
public void print(String [] sys) {
for (int i = 0; i < sys.length; i++) {
System.out.println(sys[i]);
}
}
}
public static void main(String[] args) {
//1、获取内部类的class对象
//1、1)、非静态内部类的对象需要依赖外部类的实例对象来创建
//1、2)、静态内部类可以直接通过外部类.内部类的方式创建
// String04 string04 = new String04();
// String04.S s1 = string04.new S();
String04.S1 s1 = new String04.S1();
Class<?> clazz = s1.getClass();
//2、获取method对象(首先根据方法名和参数列表确定将要操作的方法)
try {
Method method = clazz.getMethod("print", String[].class);
//3、使用invoke()方法操作指定类的方法
//3、1)、invoke()其实是有返回值的,当方法如果没有返回值类型(void)则返回null,如果有返回值类型则返回对应的返回值类型(默认是Object,需要做强制类型转换)
String [] str = {"q","w","e"};
method.invoke(s1, (Object)str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
q
w
e
关于Java反射还有一个应用实例,就是通过字符串拼接成javaBean里的get方法名,然后通过方法反射执行方法。话不多说上代码:
已知一个实体类user
package test.reflect;
public class UserReflect {
private String name;
private String sex;
private int age;
public UserReflect(String name, String sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
public UserReflect() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
应用实例:
package test.reflect;
import java.lang.reflect.Method;
/**
* 根据对象的属性名获取对象的属性值。
* 我们是通过字符串拼接成javaBean里的get方法名,然后通过方法反射执行方法。
*/
public class ReflectApplyMethod {
public static Object getValueByPropertyName(Object object, String propertyName) {
Object value = null;
//拼接Javabean中的方法,得到方法名
// String action = "get"+propertyName.substring(0, 1).toUpperCase()+propertyName.substring(1);
//通过ASCII码转换来实现首字母转大写
ReflectApplyMethod re = new ReflectApplyMethod();
String action = "get"+re.fistToUpperCase(propertyName);
System.out.println("方法名:"+action);
//通过已知对象object得到类类型
Class class1 = object.getClass();
//获取Method对象,get方法都是public,所有使用getMethod()
try {
Method m = class1.getMethod(action);
value = m.invoke(object);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
* 首字母小写转大写
* @param args
*/
public String fistToUpperCase(String name) {
char[] chars = name.toCharArray();
chars[0] -= 32;
return String.valueOf(chars);
}
/**
* 首字母大写转小写
* @param args
*/
public String fistToLowerCase(String name) {
char[] chars = name.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
public static void main(String[] args) {
//主函数调用通过属性名获取属性值的方法
UserReflect uReflect = new UserReflect("Tom", "男", 20);
System.out.println(getValueByPropertyName(uReflect, "name"));
System.out.println(getValueByPropertyName(uReflect, "sex"));
System.out.println(getValueByPropertyName(uReflect, "age"));
}
}
输出结果:
方法名:getName
Tom
方法名:getSex
男
方法名:getAge
20
3、静态导包
3.1)静态导包是Java包的静音导入,在原有基础import Java.lang.String… 上添加了static关键字,这是JDK1.5的新特性,但是只限于操作静态方法,不能操作静态变量。
import static java.lang.Integer.*;
import static java.lang.System.out;
/**
* static关键字的静态导包应用
*
*/
public class String05 {
public static void main(String[] args) {
out.println(MAX_VALUE+"&"+MIN_VALUE);
out.println(toHexString(42));
}
}
输出结果:
2147483647&-2147483648
2a
这种静态导包的好处是简化了一些操作,但是建议在有很多重复调用的时候使用,如果仅有一到两次调用,不如直接写方便。