답변: 구성 방법 없 이도 대상 을 만 들 수 있 습 니 다.
구성 방법 없 이도 대상 을 만 들 수 있다.
이전에 내 가 인용 한 단락 도 붙 여 라.
RednaxelaFX 적 혀 있 습 니 다.
네, Effective Java, Second Edition 74 조 를 추천 합 니 다.
인용 하 다.
A second cost of implementing Serializable is that it increases the likelihood
of bugs and security holes.
Normally, objects are created using constructors; serialization is an extralinguistic mechanism for creating objects. Whether you accept the default behavior or override it, deserialization is a “hidden constructor” with all of the same issues as other constructors. Because there is no
explicit constructor associated with deserialization, it is easy to forget that you
must ensure that it guarantees all of the invariants established by the constructors
and that it does not allow an attacker to gain access to the internals of the object
under construction. Relying on the default deserialization mechanism can easily
leave objects open to invariant corruption and illegal access (Item 76).
자바 언어 차원 에서 볼 때 자바 류 의 구조 기 는 두 가지 방식 으로 만 호출 될 수 있 습 니 다. 하 나 는 new 표현 식 을 통 해, 다른 하 나 는 반사 호출 구조 기 를 통 해 호출 됩 니 다.이 두 가지 방식 은 자바 프로그래머 에 게 모두 '전체' 이지 만 실제 새 대상 의 동작 은 두 단계 로 나 뉜 다.
1. 빈 대상 만 들 기 (이 때 형식 이 올 바 름), 대응 하 는 바이트 코드 는 new
2. 특정한 버 전의 구조 기 를 호출 하고 해당 바이트 코드 는 invokespecial '< init' 입 니 다.
기본 자바 반 직렬 화 체 제 는 똑 같이 두 단계 로 나 뉘 지만 다음 과 같 습 니 다.
1. 빈 대상 을 만 듭 니 다.
2. 사용자 가 정의 하 는 반 직렬 화 방법 (readObject, 있 으 면) 을 호출 하거나 기본 반 직렬 화 방법 을 호출 합 니 다.
이것 이 바로 반 서열 화 를 '숨겨 진 구조 기' 로 볼 수 있 는 이유 다.
빈 대상 을 만 들 고 싶 지만 구조 기 를 사용 하지 않 는 다 면 sun. misc. Unsafe. allocate Instance () 를 사용 해 보 세 요.
Groovy 콘 솔 로 보 여 주세요.
Groovy Shell (1.7.2, JVM: 1.6.0_23)
Type 'help' or '\h' for help.
----------------------------------------------------------------
groovy:000> class Foo {
groovy:001> int value = 12345;
groovy:002> Foo() { println "foo ctor!" }
groovy:003> int getValue() { println "getValue"; value }
groovy:004> }
===> true
groovy:000> f1 = new Foo()
foo ctor!
===> Foo@10f0625
groovy:000> f1.value
getValue
===> 12345
groovy:000> f2 = sun.misc.Unsafe.theUnsafe.allocateInstance(Foo)
===> Foo@38fff7
groovy:000> f2.value
getValue
===> 0
groovy:000> quit
f2 가 가리 키 는 Foo 대상 을 만 들 때 구조 기 는 호출 되 지 않 았 습 니 다 ("foo ctor!" 를 출력 하지 않 았 습 니 다). 인 스 턴 스 상태 (value) 도 사용자 가 지정 한 값 으로 초기 화 되 지 않 았 습 니 다 (12345). 전체 대상 의 모든 필드 는 기본 상태 (0 또는 null 또는 false 등) 에 있 습 니 다.
다만 이 화 제 를 빌려 Unsafe 예 를 들 어 자바 대상 의 생 성 은 두 단계 로 나 뉘 고 구조 기 를 호출 하 는 것 이 그 중의 한 단계 라 는 것 을 설명 한다.반 서열 화 할 때 꼭 언 세 이 프 를 썼 다 는 건 아 닙 니 다. 이 건 잘 구분 해 주세요 ^ ^
실제로 Sun JDK 의 실현 에서 자바 차원 의 반사 라 이브 러 리 와 JVM 차원 의 반사 가 서로 협력 하여 반 서열 화 를 완성 한다.java. io. Object StreamClass 는 반사 방법 / 구조 기 와 유사 한 체 제 를 호출 하여 이른바 '직렬 화 구조 기' 를 얻 고 반 직렬 화 할 때 이 버 전의 구조 기 를 호출 합 니 다.
이 '직렬 화 구조 기' 를 만 들 때 계승 체인 에서 가장 구체 적 이 고 추상 적 인 방향 으로 검색 하여 첫 번 째 직렬 화 할 수 없 는 클래스 (Serializable 인 터 페 이 스 를 실현 하지 않 은 클래스) 를 찾 아 무 참 구조 기 를 찾 아 호출 해 야 합 니 다.즉, 반 직렬 화 할 때 사용자 코드 에 명 시 된 구조 기 를 전혀 호출 하지 않 는 것 이 아니 라 Serializable 클래스 를 호출 하지 않 는 것 일 뿐이다.
구조 기 에 대해 서 는 참고 할 만 한 다른 토론 이 있 습 니 다.
인 스 턴 스 구조 기 는 정적 방법 입 니까?
======================================================================
쓰다
4. 567915. 원본 의 예 를 가지 고 실험 을 하면 문 제 를 더욱 구체 적 으로 설명 할 수 있다.
원본 코드 (조금 수정 하여 가방 이름 을 지 웠 습 니 다):
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class TestClass implements Serializable {
private static final long serialVersionUID = 0L;
public TestClass() throws Exception {
throw new Exception("!!!");
}
public static void main(String[] args) throws Exception {
byte[] head = { -84, -19, 0, 5, 115, 114, 0 };
byte[] ass = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 120, 112 };
String name = TestClass.class.getName();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(head);
baos.write(name.length());
baos.write(name.getBytes());
baos.write(ass);
baos.flush();
baos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
TestClass o = (TestClass) ois.readObject();
ois.close();
System.out.println("Created: " + o);
System.in.read(); // dump class
}
}
MyFilter:
import sun.jvm.hotspot.tools.jcore.ClassFilter;
import sun.jvm.hotspot.oops.InstanceKlass;
public class MyFilter implements ClassFilter {
@Override
public boolean canInclude(InstanceKlass kls) {
String klassName = kls.getName().asString();
return klassName.startsWith("sun/reflect/GeneratedSerializationConstructorAccessor");
}
}
컴 파일 할 때 사용:
javac -classpath ".:$JAVA_HOME/lib/sa-jdi.jar" MyFilter TestClass
그리고 먼저 실행:
java TestClass
종료 시 키 지 말고 jps 로 프로 세 스 ID 를 찾 은 다음 ClassDump 로 class 파일 을 가 져 옵 니 다.
java -classpath ".:./bin:$JAVA_HOME/lib/sa-jdi.jar" -Dsun.jvm.hotspot.tools.jcore.filter=MyFilter sun.jvm.hotspot.tools.jcore.ClassDump 7566
이렇게 해서... / sun / reflect / Generated SerializationConstructor Accessor 1. class 파일 을 얻 었 습 니 다.그러면 자바 p 로 내용 을 볼 수 있 습 니 다.
Classfile /D:/experiment/test_java_deserialize/sun/reflect/GeneratedSerializationConstructorAccessor1.class
Last modified 2010-12-23; size 1313 bytes
MD5 checksum 6d59fc9bb0c7d58458cdc76714829a0f
public class sun.reflect.GeneratedSerializationConstructorAccessor1 extends sun.reflect.SerializationConstructorAccessorImpl
minor version: 0
major version: 46
flags: ACC_PUBLIC
Constant pool: // ...
{
public sun.reflect.GeneratedSerializationConstructorAccessor1();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #36 // Method sun/reflect/SerializationConstructorAccessorImpl."<init>":()V
4: return
public java.lang.Object newInstance(java.lang.Object[]) throws java.lang.reflect.InvocationTargetException;
flags: ACC_PUBLIC
Exceptions:
throws java.lang.reflect.InvocationTargetException
Code:
stack=6, locals=2, args_size=2
0: new #6 // class TestClass
3: dup
4: aload_1
5: ifnull 24
8: aload_1
9: arraylength
10: sipush 0
13: if_icmpeq 24
16: new #22 // class java/lang/IllegalArgumentException
19: dup
20: invokespecial #29 // Method java/lang/IllegalArgumentException."<init>":()V
23: athrow
24: invokespecial #12 // Method java/lang/Object."<init>":()V
27: areturn
28: invokespecial #42 // Method java/lang/Object.toString:()Ljava/lang/String;
31: new #22 // class java/lang/IllegalArgumentException
34: dup_x1
35: swap
36: invokespecial #32 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
39: athrow
40: new #24 // class java/lang/reflect/InvocationTargetException
43: dup_x1
44: swap
45: invokespecial #35 // Method java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V
48: athrow
Exception table:
from to target type
0 24 28 Class java/lang/ClassCastException
0 24 28 Class java/lang/NullPointerException
24 27 40 Class java/lang/Throwable
}
대응 하 는 자바 코드 (표시, 안의 논 리 는 자바 로 직접 표시 할 수 없습니다. 자바 에 있 는 new 표현 식 은 생 성 대상 과 호출 구조 기 를 동시에 포함 하고 있 으 며, 이 두 동작 은 같은 유형 을 대상 으로 해 야 합 니 다. 여기 서 TestClass 를 만 든 인 스 턴 스 는 Object 의 무 참 구조 기 를 호출 합 니 다):
package sun.reflect;
public class GeneratedSerializationConstructorAccessor1
extends SerializationConstructorAccessorImpl {
public GeneratedMethodAccessor1() {
super();
}
public Object newInstance(Object[] args)
throws InvocationTargetException {
try {
// create an unitialized TestClass instance
TestClass temp = newUnitializedTestClassInstance(); // new #6 // class TestClass
// dup
// check parameters
if (args.length != 0) throw new IllegalArgumentException();
} catch (final ClassCastException | NullPointerException e) {
throw new IllegalArgumentException(e.toString());
}
// invoke Object() constructor
try {
invokeObjectConstructor(temp); // invokespecial #12 // Method java/lang/Object."<init>":()V
return temp; // areturn
} catch (Throwable t) {
throw new InvocationTargetException(t);
}
}
}
(비고: 위의 코드 는 편리 하 게 사용 되 었 습 니 다.
전에 소 개 했 던 방법. )
재 미 있 는 주석 을 유의 할 수 있다.
package sun.reflect;
/** <P> Java serialization (in java.io) expects to be able to
instantiate a class and invoke a no-arg constructor of that
class's first non-Serializable superclass. This is not a valid
operation according to the VM specification; one can not (for
classes A and B, where B is a subclass of A) write "new B;
invokespecial A()" without getting a verification error. </P>
<P> In all other respects, the bytecode-based reflection framework
can be reused for this purpose. This marker class was originally
known to the VM and verification disabled for it and all
subclasses, but the bug fix for 4486457 necessitated disabling
verification for all of the dynamically-generated bytecodes
associated with reflection. This class has been left in place to
make future debugging easier. </P> */
abstract class SerializationConstructorAccessorImpl
extends ConstructorAccessorImpl {
}
관련 된 주목 할 만 한 방법 과 유형 은 다음 과 같다.
java.io.ObjectStreamClass.getSerializableConstructor()
sun.reflect.ReflectionFactory.newConstructorForSerialization()
sun.reflect.MethodAccessorGenerator.generateSerializationConstructor()
sun.reflect.SerializationConstructorAccessorImpl
======================================================================
위 에 서 는 Sun JDK 로 역 직렬 화 가능 한 실현 방식 을 보 여 주 었 다.사실 Sun JDK 도 1.4 부터 이런 방식 을 사 용 했 고, 기 존 에는 다른 방식 을 사용 했다.이 방식 은 검증 (verification) 을 통과 할 수 없 는 바이트 코드 시퀀스 를 사 용 했 습 니 다. 억지로 하려 는 말 은 JVM 규범 과 충돌 합 니 다.이 를 실행 할 수 있 도록 HotSpot VM 에 서 는 전문 적 으로 뒷문 을 열 었 다.
'규범' 과 실현 간 의 차 이 를 잘 구분 하 세 요.
규범 은 일반적으로 비교적 빡빡 하 게 정 해 져 있 으 며, 실현 은 많은 곳 에서 '지름길 로' 갈 수 있 습 니 다. 위의 사용자 가 지름길 로 가 는 것 을 감지 하지 못 하 게 하면 문제 없습니다. ∩ ^ ^∩
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.