通过static关键字引发的一些知识点,static关键字知识点


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

这种静态导包的好处是简化了一些操作,但是建议在有很多重复调用的时候使用,如果仅有一到两次调用,不如直接写方便。

相关内容

    暂无相关文章