类的加载:
类加载器:
其实在java中有三种类类加载器。
1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
初始化:
(主要是对静态变量的一些初始化)
1.下面是当用final修饰的static变量的初始化的两个例子:
- 如果一个静态属性使用final修饰,如果它的值可以在编译时得到,系统会认为该类被被动使用,将不会对该类进行初始化.
- 反之,如果不能再编译时得到,其值必须在运行时才能确定,则会对类进行初始化。
public class JavaTest {
public static void main(String[] args) {
System.out.println(B.test1);//执行此句不对类初始化。
System.out.println(B.test2);//执行此句对类初始化
}
}
//使用final修饰的static变量与类初始化的关系
class B{
static{//如果没有初始化将不被打印
System.out.println("静态初始化块。。。//被初始化时打印");
}
static final String test1="如果一个静态属性使用final修饰,如果它的值可以在编译时得到,系统会认为该类被被动使用,将不会对该类进行初始化";
static final String test2=System.currentTimeMillis()+"";
}
2.当使用ClassLoader.loadClass()加载某个类时,该方法只是加载类,不执行初始化Class.forName()才执行初始化。
public class JavaTest {
public static void main(String[] args) throws ClassNotFoundException {//注意可能会抛出类未找到异常
ClassLoader c = ClassLoader.getSystemClassLoader();
c.loadClass("C");//不执行对类C的初始化
//System.out.println(c);//可以输出系统类加载器
Class.forName("C");//执行对类C的初始化(反射)
}
}
//ClassLoader.loadClass() 与 Class.forName()
class C{
static{//如果没有初始化将不被打印
System.out.println("静态初始化块。。。//被初始化时打印");
}
}
反射:
- 可以查看类的信息
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class JavaTest {
//定义一个私有构造器
private JavaTest(){
}
//定义一个有参构造方法
public JavaTest(String name){
}
//定义一个有参构造方法
public JavaTest(int name){
}
//定义一个无参数方法
public void info(){
System.out.println("执行无参数info");
}
//有参
public void info(String name){
System.out.println("执行有参info:"+name);
}
//测试用的内部类
class Inner{
}
public static void main(String[] args) throws ClassNotFoundException{
//获取Class
Class<JavaTest> c=JavaTest.class;
System.out.println(c);
//得到所有构造器(包括私有的),而getConstructors()是得到全部public构造器
Constructor[] constructors=c.getDeclaredConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
System.out.println(constructor);
}
//得到全部方法,同上
Method[] methods=c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//得到内部类
Class[] inner =c.getDeclaredClasses();
for (Class class1 : inner) {
System.out.println(class1);
}
Class inClass =Class.forName("JavaTest$Inner");
System.out.println("该内部类的外部类为:"+inClass.getDeclaringClass());
System.out.println("包名:"+c.getPackage());
}
}
利用反射生成对象
- 使用Class对象的newInstance()方法,调用的是默认构造器
- 使用Class获取指定的构造器,再用该构造器的newInstance()
另外,一个使用反射的好例子:
/**
* @author Rollen-Holt 设计模式之 工厂模式
*/
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 构造工厂类
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{
public static fruit getInstance(String fruitName){
fruit f=null;
if("Apple".equals(fruitName)){
f=new Apple();
}
if("Orange".equals(fruitName)){
f=new Orange();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Orange");
f.eat();
}
}
package Reflect;
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Reflect.Apple");
if(f!=null){
f.eat();
}
}
}
现在就算我们添加任意多个子类的时候,工厂类就不需要修改。
上面的代码虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
下面我们来看看: 结合属性文件的工厂模式
首先创建一个fruit.properties的资源文件,
内容为:
apple=Reflect.Apple
orange=Reflect.Orange
然后编写主类代码:
package Reflect;
import java.io.*;
import java.util.*;
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
//操作属性文件类
class init{
public static Properties getPro() throws FileNotFoundException, IOException{
Properties pro=new Properties();
File f=new File("fruit.properties");
if(f.exists()){
pro.load(new FileInputStream(f));
}else{
pro.setProperty("apple", "Reflect.Apple");
pro.setProperty("orange", "Reflect.Orange");
pro.store(new FileOutputStream(f), "FRUIT CLASS");
}
return pro;
}
}
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a) throws FileNotFoundException, IOException{
Properties pro=init.getPro();
fruit f=Factory.getInstance(pro.getProperty("apple"));
if(f!=null){
f.eat();
}
}
}