这个是不能自己调用创建的,可以调用instance()方法返回我知道单例模式不是自己 new 对象,但是你的代码里调用 getInstance 也一样会出错
这个是不能自己调用创建的,可以调用instance()方法返回class Single {
private static Single instance;
static { try{ new InitError(); }catch(Throwable t){ t.printStackTrace(); } }
public static Single instance(){ return instance; }
public Single(){ InitError.o.fun(); }
private static class InitError { static InitError o = new InitError();
static { Single.instance = new Single(); throwError(); }
static void throwError(){ throw new IllegalAccessError(); }
void fun(){ } } }public class Test9 { public static void main(String[] args){ Single s1 = Single.instance(); System.out.println(s1.getClass().getName()); } }java.lang.IllegalAccessError com.idbk.ismart.java.demo.Single at com.idbk.ismart.java.demo.Single$InitError.throwError(Test9.java:32) at com.idbk.ismart.java.demo.Single$InitError.<clinit>(Test9.java:28) at com.idbk.ismart.java.demo.Single.<clinit>(Test9.java:9) at com.idbk.ismart.java.demo.Test9.main(Test9.java:43)
简单的不让创建再二次对象的方式可以这样 设置私有构造器,这样不会被使用者通过 new 来创建,然后一个 public final 的属性并且赋个初值 class MySingle {
public static final MySingle instance = new MySingle();
private MySingle(){ if(instance != null) throw new RuntimeException("只能创建一个对象"); else System.out.println("第一次创建对象!"); } } 但是,java 支持反射(C#也支持反射),有了反射就可以绕过一些限制访问类的成员,以下代码可以在单例模式下创建多个对象 class MySingle {
public static final MySingle instance = new MySingle();
private MySingle(){ if(instance != null) throw new RuntimeException("只能创建一个对象"); else System.out.println("第一次创建对象!"); } }public class Test9 { public static void main(String[] args) throws Exception { // Single s1 = Single.instance(); // System.out.println(s1.getClass().getName());
static { try{ new InitError(); }catch(Throwable t){ t.printStackTrace(); } }
public static Single instance(){ return instance; }
public Single(){ InitError.o.fun(); }
private static class InitError { static InitError o = new InitError();
static { Single.instance = new Single(); throwError(); }
static void throwError(){ throw new IllegalAccessError(); }
void fun(){ } } }public class Test9 { public static void main(String[] args){ Single s1 = Single.instance(); System.out.println(s1.getClass().getName()); } }java.lang.IllegalAccessError com.idbk.ismart.java.demo.Single at com.idbk.ismart.java.demo.Single$InitError.throwError(Test9.java:32) at com.idbk.ismart.java.demo.Single$InitError.<clinit>(Test9.java:28) at com.idbk.ismart.java.demo.Single.<clinit>(Test9.java:9) at com.idbk.ismart.java.demo.Test9.main(Test9.java:43)上面的错误已经捕获,你的程序并没有终止,获取的单列可以使用
private static Single instance;
static {
try{
new InitError();
}catch(Throwable t){
t.printStackTrace();
}
}
public static Single instance(){
return instance;
}
public Single(){
InitError.o.fun();
}
private static class InitError {
static InitError o = new InitError();
static {
Single.instance = new Single();
throwError();
}
static void throwError(){
throw new IllegalAccessError();
}
void fun(){
}
}
}public class Test9 { public static void main(String[] args){
Single s1 = Single.instance();
System.out.println(s1.getClass().getName());
}
}java.lang.IllegalAccessError
com.idbk.ismart.java.demo.Single
at com.idbk.ismart.java.demo.Single$InitError.throwError(Test9.java:32)
at com.idbk.ismart.java.demo.Single$InitError.<clinit>(Test9.java:28)
at com.idbk.ismart.java.demo.Single.<clinit>(Test9.java:9)
at com.idbk.ismart.java.demo.Test9.main(Test9.java:43)
设置私有构造器,这样不会被使用者通过 new 来创建,然后一个 public final 的属性并且赋个初值
class MySingle {
public static final MySingle instance = new MySingle();
private MySingle(){
if(instance != null)
throw new RuntimeException("只能创建一个对象");
else
System.out.println("第一次创建对象!");
}
}
但是,java 支持反射(C#也支持反射),有了反射就可以绕过一些限制访问类的成员,以下代码可以在单例模式下创建多个对象
class MySingle {
public static final MySingle instance = new MySingle();
private MySingle(){
if(instance != null)
throw new RuntimeException("只能创建一个对象");
else
System.out.println("第一次创建对象!");
}
}public class Test9 { public static void main(String[] args) throws Exception {
// Single s1 = Single.instance();
// System.out.println(s1.getClass().getName());
try{
MySingle obj1 = MySingle.instance;
System.out.println(obj1.getClass().getName());
}catch(Exception ex){
ex.printStackTrace();
}
try{
// 利用反射调用类的私有构造器(失败)
Class<? extends MySingle> cls = MySingle.class;
java.lang.reflect.Constructor<? extends MySingle> constructor = cls.getDeclaredConstructor();
constructor.setAccessible(true);
MySingle obj2 = constructor.newInstance();
System.out.println(obj2.getClass().getName());
}catch(Exception ex){
ex.printStackTrace();
}
try{
// 利用反射清除 MySingle.instance值,然后再次利用反射调用类构造器
Class<? extends MySingle> cls = MySingle.class;
java.lang.reflect.Field instanceField = cls.getDeclaredField("instance");
instanceField.setAccessible(true);
// 先清除 instance 的 final 属性
java.lang.reflect.Field modifierField = java.lang.reflect.Field.class.getDeclaredField("modifiers");
modifierField.setAccessible(true);
modifierField.set(instanceField, instanceField.getModifiers() & ~java.lang.reflect.Modifier.FINAL);
instanceField.set(null, null);
java.lang.reflect.Constructor<? extends MySingle> constructor = cls.getDeclaredConstructor();
constructor.setAccessible(true);
MySingle obj3 = constructor.newInstance();
System.out.println(obj3.getClass().getName());
}catch(Exception ex){
ex.printStackTrace();
}
}
}
private static Single instance;
static {
try{
new InitError();
}catch(Throwable t){
t.printStackTrace();
}
}
public static Single instance(){
return instance;
}
public Single(){
InitError.o.fun();
}
private static class InitError {
static InitError o = new InitError();
static {
Single.instance = new Single();
throwError();
}
static void throwError(){
throw new IllegalAccessError();
}
void fun(){
}
}
}public class Test9 { public static void main(String[] args){
Single s1 = Single.instance();
System.out.println(s1.getClass().getName());
}
}java.lang.IllegalAccessError
com.idbk.ismart.java.demo.Single
at com.idbk.ismart.java.demo.Single$InitError.throwError(Test9.java:32)
at com.idbk.ismart.java.demo.Single$InitError.<clinit>(Test9.java:28)
at com.idbk.ismart.java.demo.Single.<clinit>(Test9.java:9)
at com.idbk.ismart.java.demo.Test9.main(Test9.java:43)上面的错误已经捕获,你的程序并没有终止,获取的单列可以使用