Java Exception & RTTI
Exception
Try
{
... ...
}
catch (Exception ex)
{
…;
throw new Throwable(ex);
}
catch (Throwable ex)
{
…;
}
finally
{ }
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import libcore.util.EmptyArray; /**
* The superclass of all classes which can be thrown by the VM. The
* two direct subclasses are recoverable exceptions ({@code Exception}) and
* unrecoverable errors ({@code Error}). This class provides common methods for
* accessing a string message which provides extra information about the
* circumstances in which the {@code Throwable} was created (basically an error
* message in most cases), and for saving a stack trace (that is, a record of
* the call stack at a particular point in time) which can be printed later.
* <p>
* A {@code Throwable} can also include a cause, which is a nested {@code
* Throwable} that represents the original problem that led to this {@code
* Throwable}. It is often used for wrapping various types of errors into a
* common {@code Throwable} without losing the detailed original error
* information. When printing the stack trace, the trace of the cause is
* included.
*
* @see Error
* @see Exception
* @see RuntimeException
*/
public class Throwable implements java.io.Serializable {
private static final long serialVersionUID = -3042686055658047285L; /**
* The message provided when the exception was created.
*/
private String detailMessage; /**
* The cause of this Throwable. Null when there is no cause.
*/
private Throwable cause = this; /**
* Throwables suppressed by this throwable. Null when suppressed exceptions
* are disabled.
*/
private List<Throwable> suppressedExceptions = new ArrayList<Throwable>(); /**
* An intermediate representation of the stack trace. This field may
* be accessed by the VM; do not rename.
*/
private volatile Object stackState; /**
* A fully-expanded representation of the stack trace.
*/
private StackTraceElement[] stackTrace; /**
* Constructs a new {@code Throwable} that includes the current stack trace.
*/
public Throwable() {
fillInStackTrace();
} /**
* Constructs a new {@code Throwable} with the current stack trace and the
* specified detail message.
*
* @param detailMessage
* the detail message for this {@code Throwable}.
*/
public Throwable(String detailMessage) {
this();
this.detailMessage = detailMessage;
} /**
* Constructs a new {@code Throwable} with the current stack trace, the
* specified detail message and the specified cause.
*
* @param detailMessage
* the detail message for this {@code Throwable}.
* @param throwable
* the cause of this {@code Throwable}.
*/
public Throwable(String detailMessage, Throwable throwable) {
this();
this.detailMessage = detailMessage;
cause = throwable;
} /**
* Constructs a new {@code Throwable} with the current stack trace and the
* specified cause.
*
* @param throwable
* the cause of this {@code Throwable}.
*/
public Throwable(Throwable throwable) {
this();
this.detailMessage = throwable == null ? null : throwable.toString();
cause = throwable;
} /**
* Constructs a new {@code Throwable} with the current stack trace, the
* specified detail message and the specified cause.
*
* @param enableSuppression if false, throwables passed to {@link
* #addSuppressed(Throwable)} will be silently discarded.
* @since 1.7
* @hide 1.7
*/
protected Throwable(String detailMessage, Throwable throwable, boolean enableSuppression) {
this(detailMessage, throwable);
if (!enableSuppression) {
this.suppressedExceptions = null;
}
} /**
* Records the stack trace from the point where this method has been called
* to this {@code Throwable}. This method is invoked by the {@code Throwable} constructors.
*
* <p>This method is public so that code (such as an RPC system) which catches
* a {@code Throwable} and then re-throws it can replace the construction-time stack trace
* with a stack trace from the location where the exception was re-thrown, by <i>calling</i>
* {@code fillInStackTrace}.
*
* <p>This method is non-final so that non-Java language implementations can disable VM stack
* traces for their language. Filling in the stack trace is relatively expensive.
* <i>Overriding</i> this method in the root of a language's exception hierarchy allows the
* language to avoid paying for something it doesn't need.
*
* @return this {@code Throwable} instance.
*/
public Throwable fillInStackTrace() {
// Fill in the intermediate representation
stackState = nativeFillInStackTrace();
// Mark the full representation as empty
stackTrace = null;
return this;
} /**
* Returns the extra information message which was provided when this
* {@code Throwable} was created. Returns {@code null} if no message was
* provided at creation time.
*
* @return this {@code Throwable}'s detail message.
*/
public String getMessage() {
return detailMessage;
} /**
* Returns the extra information message which was provided when this
* {@code Throwable} was created. Returns {@code null} if no message was
* provided at creation time. Subclasses may override this method to return
* localized text for the message. Android returns the regular detail message.
*
* @return this {@code Throwable}'s localized detail message.
*/
public String getLocalizedMessage() {
return getMessage();
} /**
* Returns the array of stack trace elements of this {@code Throwable}. Each
* {@code StackTraceElement} represents an entry in the call stack. The
* element at position 0 is the top of the stack, that is, the stack frame
* where this {@code Throwable} is thrown.
*
* @return a copy of the array of {@code StackTraceElement}s representing
* the call stack. Changes in the array obtained from this call will
* not change the call stack stored in this {@code Throwable}.
* @see #printStackTrace()
*/
public StackTraceElement[] getStackTrace() {
return getInternalStackTrace().clone();
} /**
* Sets the array of stack trace elements. Each {@code StackTraceElement}
* represents an entry in the call stack. A copy of the specified array is
* stored in this {@code Throwable}. will be returned by {@code
* getStackTrace()} and printed by {@code printStackTrace()}.
*
* @param trace
* the new array of {@code StackTraceElement}s. A copy of the
* array is stored in this {@code Throwable}, so subsequent
* changes to {@code trace} will not change the call stack stored
* in this {@code Throwable}.
* @throws NullPointerException
* if any element in {@code trace} is {@code null}.
* @see #printStackTrace()
*/
public void setStackTrace(StackTraceElement[] trace) {
StackTraceElement[] newTrace = trace.clone();
for (StackTraceElement element : newTrace) {
if (element == null) {
throw new NullPointerException();
}
}
stackTrace = newTrace;
} /**
* Writes a printable representation of this {@code Throwable}'s stack trace
* to the {@code System.err} stream.
*
*/
public void printStackTrace() {
printStackTrace(System.err);
} /**
* Counts the number of duplicate stack frames, starting from the
* end of the stack.
*
* @param currentStack a stack to compare
* @param parentStack a stack to compare
*
* @return the number of duplicate stack frames.
*/
private static int countDuplicates(StackTraceElement[] currentStack,
StackTraceElement[] parentStack) {
int duplicates = 0;
int parentIndex = parentStack.length;
for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
StackTraceElement parentFrame = parentStack[parentIndex];
if (parentFrame.equals(currentStack[i])) {
duplicates++;
} else {
break;
}
}
return duplicates;
} /**
* Returns an array of StackTraceElement. Each StackTraceElement
* represents a entry on the stack.
*
* @return an array of StackTraceElement representing the stack
*/
private StackTraceElement[] getInternalStackTrace() {
if (stackTrace == null) {
stackTrace = nativeGetStackTrace(stackState);
stackState = null; // Clean up intermediate representation
}
return stackTrace;
} /**
* Writes a printable representation of this {@code Throwable}'s stack trace
* to the specified print stream. If the {@code Throwable} contains a
* {@link #getCause() cause}, the method will be invoked recursively for
* the nested {@code Throwable}.
*
* @param err
* the stream to write the stack trace on.
*/
public void printStackTrace(PrintStream err) {
try {
printStackTrace(err, "", null);
} catch (IOException e) {
// Appendable.append throws IOException but PrintStream.append doesn't.
throw new AssertionError();
}
} /**
* Writes a printable representation of this {@code Throwable}'s stack trace
* to the specified print writer. If the {@code Throwable} contains a
* {@link #getCause() cause}, the method will be invoked recursively for the
* nested {@code Throwable}.
*
* @param err
* the writer to write the stack trace on.
*/
public void printStackTrace(PrintWriter err) {
try {
printStackTrace(err, "", null);
} catch (IOException e) {
// Appendable.append throws IOException, but PrintWriter.append doesn't.
throw new AssertionError();
}
} /**
* @param indent additional indentation on each line of the stack trace.
* This is the empty string for all but suppressed throwables.
* @param parentStack the parent stack trace to suppress duplicates from, or
* null if this stack trace has no parent.
*/
private void printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack)
throws IOException {
err.append(toString());
err.append("\n"); StackTraceElement[] stack = getInternalStackTrace();
if (stack != null) {
int duplicates = parentStack != null ? countDuplicates(stack, parentStack) : 0;
for (int i = 0; i < stack.length - duplicates; i++) {
err.append(indent);
err.append("\tat ");
err.append(stack[i].toString());
err.append("\n");
} if (duplicates > 0) {
err.append(indent);
err.append("\t... ");
err.append(Integer.toString(duplicates));
err.append(" more\n");
}
} // Print suppressed exceptions indented one level deeper.
if (suppressedExceptions != null) {
for (Throwable throwable : suppressedExceptions) {
err.append(indent);
err.append("\tSuppressed: ");
throwable.printStackTrace(err, indent + "\t", stack);
}
} Throwable cause = getCause();
if (cause != null) {
err.append(indent);
err.append("Caused by: ");
cause.printStackTrace(err, indent, stack);
}
} @Override
public String toString() {
String msg = getLocalizedMessage();
String name = getClass().getName();
if (msg == null) {
return name;
}
return name + ": " + msg;
} /**
* Initializes the cause of this {@code Throwable}. The cause can only be
* initialized once.
*
* @param throwable
* the cause of this {@code Throwable}.
* @return this {@code Throwable} instance.
* @throws IllegalArgumentException
* if {@code Throwable} is this object.
* @throws IllegalStateException
* if the cause has already been initialized.
*/
public Throwable initCause(Throwable throwable) {
if (cause != this) {
throw new IllegalStateException("Cause already initialized");
}
if (throwable == this) {
throw new IllegalArgumentException("throwable == this");
}
cause = throwable;
return this;
} /**
* Returns the cause of this {@code Throwable}, or {@code null} if there is
* no cause.
*
* @return Throwable this {@code Throwable}'s cause.
*/
public Throwable getCause() {
if (cause == this) {
return null;
}
return cause;
} /**
* Adds {@code throwable} to the list of throwables suppressed by this. The
* throwable will included when this exception's stack trace is printed.
*
* @throws IllegalArgumentException if {@code throwable == this}.
* @throws NullPointerException if {@code throwable == null}.
* @since 1.7
* @hide 1.7
*/
public final void addSuppressed(Throwable throwable) {
if (throwable == this) {
throw new IllegalArgumentException("suppressed == this");
}
if (throwable == null) {
throw new NullPointerException("suppressed == null");
}
if (suppressedExceptions != null) {
suppressedExceptions.add(throwable);
}
} /**
* Returns the throwables suppressed by this.
*
* @since 1.7
* @hide 1.7
*/
public final Throwable[] getSuppressed() {
return (suppressedExceptions != null)
? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
: EmptyArray.THROWABLE;
} private void writeObject(ObjectOutputStream out) throws IOException {
// ensure the stackTrace field is initialized
getInternalStackTrace();
out.defaultWriteObject();
} private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); if (suppressedExceptions != null) {
// the deserialized list may be unmodifiable, so just create a mutable copy
suppressedExceptions = new ArrayList<Throwable>(suppressedExceptions);
}
} /*
* Creates a compact, VM-specific collection of goodies, suitable for
* storing in the "stackState" field, based on the current thread's
* call stack.
*/
private static native Object nativeFillInStackTrace(); /*
* Creates an array of StackTraceElement objects from the data held
* in "stackState".
*/
private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang; /**
* {@code Exception} is the superclass of all classes that represent recoverable
* exceptions. When exceptions are thrown, they may be caught by application
* code.
*
* @see Throwable
* @see Error
* @see RuntimeException
*/
public class Exception extends Throwable {
private static final long serialVersionUID = -3387516993124229948L; /**
* Constructs a new {@code Exception} that includes the current stack trace.
*/
public Exception() {
} /**
* Constructs a new {@code Exception} with the current stack trace and the
* specified detail message.
*
* @param detailMessage
* the detail message for this exception.
*/
public Exception(String detailMessage) {
super(detailMessage);
} /**
* Constructs a new {@code Exception} with the current stack trace, the
* specified detail message and the specified cause.
*
* @param detailMessage
* the detail message for this exception.
* @param throwable
* the cause of this exception.
*/
public Exception(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
} /**
* Constructs a new {@code Exception} with the current stack trace and the
* specified cause.
*
* @param throwable
* the cause of this exception.
*/
public Exception(Throwable throwable) {
super(throwable);
}
}
- Java的基本原理就是“形式错误的代码不会运行”。
- 与C++类似,捕获错误最理想的是在编译期间,最好在试图运行程序以前。
- “违例条件”表示在出现什么问题的时候应中止方法或作用域的继续。为了将违例条件与普通问题区分开,违例条件是非常重要的一个因素。而在违例条件的情况下,却无法继续下去,因为当地没有提供解决问题所需的足够多的信息。此时,我们能做的唯一事情就是跳出当地环境,将那个问题委托给一个更高级的负责人。这便是出现违例时出现的情况。
- 首先,按照与创建Java对象一样的方法创建违例对象:在内存“堆”里,使用new来创建。随后,停止当前执行路径(记住不可沿这条路径继续下去),然后从当前的环境中释放出违例对象的句柄。此时,违例控制机制会接管一切,并开始查找一个恰当的地方,用于继续程序的执行。这个恰当的地方便是“违例控制器”,它的职责是从问题中恢复,使程序要么尝试另一条执行路径,要么简单地继续。
- 和Java的其他任何对象一样,需要用new在内存堆里创建违例,并需调用一个构建器。在所有标准违例中,存在着两个构建器:第一个是默认构建器,第二个则需使用一个字串自变量,使我们能在违例里置入相关信息.
- 若某个方法产生一个违例,必须保证该违例能被捕获,并获得正确对待。对于Java的违例控制机制,它的一个好处就是允许我们在一个地方将精力集中在要解决的问题上,然后在另一个地方对待来自那个代码内部的错误。
- 若位于一个方法内部,并“掷”出一个违例(或在这个方法内部调用的另一个方法产生了违例),那个方法就会在违例产生过程中退出。若不想一个throw离开方法,可在那个方法内部设置一个特殊的代码块,用它捕获违例。这就叫作“try块”,因为要在这个地方“尝试”各种方法调用。try块属于一种普通的作用域,用一个try关键字开头:
try {// 可能产生违例的代码} - 当然,生成的违例必须在某个地方中止。这个“地方”便是违例控制器或者违例控制模块。而且针对想捕获的每种违例类型,都必须有一个相应的违例控制器。违例控制器紧接在try块后面,且用catch(捕获)关键字标记。
- 控制器必须“紧接”在try块后面。若“掷”出一个违例,违例控制机制就会搜寻自变量与违例类型相符的第一个控制器。随后,它会进入那个catch从句,并认为违例已得到控制(一旦catch从句结束,对控制器的搜索也会停止)。只有相符的catch从句才会得到执行;它与switch语句不同,后者在每个case后都需要一个break命令,防止误执行其他语句。在try块内部,请注意大量不同的方法调用可能生成相同的违例,但只需要一个控制器。
- 违例规范采用了一个额外的关键字:throws;后面跟随全部潜在的违例类型。
- 假若方法造成了一个违例,但没有对其进行控制,编译器会侦测到这个情况,并告诉我们必须控制违例,或者指出应该从方法里“掷”出一个违例规范。通过坚持从顶部到底部排列违例规范,Java可在编译期保证违例的正确性(注释②)。
- 我们可创建一个控制器,令其捕获所有类型的违例。具体的做法是捕获基础类违例类型Exception(也存在其他类型的基础违例,但Exception是适用于几乎所有编程活动的基础)。
- 在某些情况下,我们想重新掷出刚才产生过的违例,特别是在用Exception捕获所有可能的违例时。由于我们已拥有当前违例的句柄,所以只需简单地重新掷出那个句柄即可. 重新“掷”出一个违例导致违例进入更高一级环境的违例控制器中。用于同一个try块的任何更进一步的catch从句仍然会被忽略。此外,与违例对象有关的所有东西都会得到保留,所以用于捕获特定违例类型的更高一级的控制器可以从那个对象里提取出所有信息。
- Throwable类必须在违例规格中出现,因为fillInStackTrace()会生成一个Throwable对象的句柄。由于Throwable是Exception的一个基础类,所以有可能获得一个能够“掷”出的对象(具有Throwable属性),但却并非一个Exception(违例)。因此,在main()中用于Exception的句柄可能丢失自己的目标。为保证所有东西均井然有序,编译器强制Throwable使用一个违例规范。
- Java包含了一个名为Throwable的类,它对可以作为违例“掷”出的所有东西进行了描述。Throwable对象有两种常规类型(亦即“从Throwable继承”)。其中,Error代表编译期和系统错误,我们一般不必特意捕获它们(除在特殊情况以外)。Exception是可以从任何标准Java库的类方法中“掷”出的基本类型。此外,它们亦可从我们自己的方法以及运行期偶发事件中“掷”出。
- 由于编译器并不强制违例规范捕获它们,所以假如不捕获的话,一个RuntimeException可能过滤掉我们到达main()方法的所有途径。
- 假若一个RuntimeException获得到达main()的所有途径,同时不被捕获,那么当程序退出时,会为那个违例调用printStackTrace()。注意也许能在自己的代码中仅忽略RuntimeException,因为编译器已正确实行了其他所有控制。因为RuntimeException在此时代表一个编程错误:(1) 一个我们不能捕获的错误(例如,由客户程序员接收传递给自己方法的一个空句柄)。(2) 作为一名程序员,一个应在自己的代码中检查的错误(如ArrayIndexOutOfBoundException,此时应注意数组的大小)。
- 为创建自己的违例类,必须从一个现有的违例类型继承——最好在含义上与新违例近似。在第二个构建器中,通过使用super关键字,明确调用了带有一个String参数的基础类构建器。
- 覆盖一个方法时,只能产生已在方法的基础类版本中定义的违例。这是一个重要的限制,因为它意味着与基础类协同工作的代码也会自动应用于从基础类衍生的任何对象(当然,这属于基本的OOP概念),其中包括违例。
- C++施加了类似的限制,要求衍生方法违例与基础类方法掷出的违例相同,或者从后者衍生。在这种情况下,C++实际上能够在编译期间检查违例规范。
- 尽管违例规范是由编译器在继承期间强行遵守的,但违例规范并不属于方法类型的一部分,后者仅包括了方法名以及自变量类型。因此,我们不可在违例规范的基础上覆盖方法。除此以外,尽管违例规范存在于一个方法的基础类版本中,但并不表示它必须在方法的衍生类版本中存在。这与方法的“继承”颇有不同(进行继承时,基础类中的方法也必须在衍生类中存在)。换言之,用于一个特定方法的“违例规范接口”可能在继承和覆盖时变得更“窄”,但它不会变得更“宽”——这与继承时的类接口规则是正好相反的。
- 无论一个违例是否在try块中发生,我们经常都想执行一些特定的代码。对一些特定的操作,经常都会遇到这种情况,但在恢复内存时一般都不需要(因为垃圾收集器会自动照料一切)。为达到这个目的,可在所有违例控制器的末尾使用一个finally从句(注释④)。
- 在没有“垃圾收集”以及“自动调用破坏器”机制的一种语言中(注释⑤),finally显得特别重要,因为程序员可用它担保内存的正确释放——无论在try块内部发生了什么状况。但Java提供了垃圾收集机制,所以内存的释放几乎绝对不会成为问题。另外,它也没有构建器可供调用。
- “破坏器”(Destructor)是“构建器”(Constructor)的反义词。它代表一个特殊的函数,一旦某个对象失去用处,通常就会调用它。我们肯定知道在哪里以及何时调用破坏器。C++提供了自动的破坏器调用机制,但Delphi的Object Pascal版本1及2却不具备这一能力(在这种语言中,破坏器的含义与用法都发生了变化)。
- “掷”出一个违例后,违例控制系统会按当初编写的顺序搜索“最接近”的控制器。一旦找到相符的控制器,就认为违例已得到控制,不再进行更多的搜索工作。在违例和它的控制器之间,并不需要非常精确的匹配。一个衍生类对象可与基础类的一个控制器相配.
- 用违例做下面这些事情:
(1) 解决问题并再次调用造成违例的方法。
(2) 平息事态的发展,并在不重新尝试方法的前提下继续。
(3) 计算另一些结果,而不是希望方法产生的结果。
(4) 在当前环境中尽可能解决问题,以及将相同的违例重新“掷”出一个更高级的环境。
(5) 在当前环境中尽可能解决问题,以及将不同的违例重新“掷”出一个更高级的环境。
(6) 中止程序执行。
(7) 简化编码。若违例方案使事情变得更加复杂,那就会令人非常烦恼,不如不用。
(8) 使自己的库和程序变得更加安全。这既是一种“短期投资”(便于调试),也是一种“长期投资”(改善应用程序的健壮性)
RTTI = Running-Time Type
Identification
Class
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2006-2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang; import dalvik.system.VMStack;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.net.URL;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import libcore.util.CollectionUtils;
import libcore.util.EmptyArray;
import org.apache.harmony.kernel.vm.StringUtils;
import org.apache.harmony.luni.lang.reflect.GenericSignatureParser;
import org.apache.harmony.luni.lang.reflect.Types; /**
* The in-memory representation of a Java class. This representation serves as
* the starting point for querying class-related information, a process usually
* called "reflection". There are basically three types of {@code Class}
* instances: those representing real classes and interfaces, those representing
* primitive types, and those representing array classes.
*
* <h4>Class instances representing object types (classes or interfaces)</h4>
* <p>
* These represent an ordinary class or interface as found in the class
* hierarchy. The name associated with these {@code Class} instances is simply
* the fully qualified class name of the class or interface that it represents.
* In addition to this human-readable name, each class is also associated by a
* so-called <em>signature</em>, which is the letter "L", followed by the
* class name and a semicolon (";"). The signature is what the runtime system
* uses internally for identifying the class (for example in a DEX file).
* </p>
* <h4>Classes representing primitive types</h4>
* <p>
* These represent the standard Java primitive types and hence share their
* names (for example "int" for the {@code int} primitive type). Although it is
* not possible to create new instances based on these {@code Class} instances,
* they are still useful for providing reflection information, and as the
* component type of array classes. There is one {@code Class} instance for each
* primitive type, and their signatures are:
* </p>
* <ul>
* <li>{@code B} representing the {@code byte} primitive type</li>
* <li>{@code S} representing the {@code short} primitive type</li>
* <li>{@code I} representing the {@code int} primitive type</li>
* <li>{@code J} representing the {@code long} primitive type</li>
* <li>{@code F} representing the {@code float} primitive type</li>
* <li>{@code D} representing the {@code double} primitive type</li>
* <li>{@code C} representing the {@code char} primitive type</li>
* <li>{@code Z} representing the {@code boolean} primitive type</li>
* <li>{@code V} representing void function return values</li>
* </ul>
* <p>
* <h4>Classes representing array classes</h4>
* <p>
* These represent the classes of Java arrays. There is one such {@code Class}
* instance per combination of array leaf component type and arity (number of
* dimensions). In this case, the name associated with the {@code Class}
* consists of one or more left square brackets (one per dimension in the array)
* followed by the signature of the class representing the leaf component type,
* which can be either an object type or a primitive type. The signature of a
* {@code Class} representing an array type is the same as its name. Examples
* of array class signatures are:
* </p>
* <ul>
* <li>{@code [I} representing the {@code int[]} type</li>
* <li>{@code [Ljava/lang/String;} representing the {@code String[]} type</li>
* <li>{@code [[[C} representing the {@code char[][][]} type (three dimensions!)</li>
* </ul>
*/
public final class Class<T> implements Serializable, AnnotatedElement, GenericDeclaration, Type { private static final long serialVersionUID = 3206093459760846163L; /**
* Lazily computed name of this class; always prefer calling getName().
*/
private transient String name; private Class() {
// Prevent this class to be instantiated, instance
// should be created by JVM only
} /**
* Get the Signature attribute for this class. Returns null if not found.
*/
private String getSignatureAttribute() {
Object[] annotation = getSignatureAnnotation(); if (annotation == null) {
return null;
} return StringUtils.combineStrings(annotation);
} /**
* Get the Signature annotation for this class. Returns null if not found.
*/
native private Object[] getSignatureAnnotation(); /**
* Returns a {@code Class} object which represents the class with the
* specified name. The name should be the name of a class as described in
* the {@link Class class definition}; however, {@code Class}es representing
* primitive types can not be found using this method.
* <p>
* If the class has not been loaded so far, it is being loaded and linked
* first. This is done through either the class loader of the calling class
* or one of its parent class loaders. The class is also being initialized,
* which means that a possible static initializer block is executed.
*
* @param className
* the name of the non-primitive-type class to find.
* @return the named {@code Class} instance.
* @throws ClassNotFoundException
* if the requested class can not be found.
* @throws LinkageError
* if an error occurs during linkage
* @throws ExceptionInInitializerError
* if an exception occurs during static initialization of a
* class.
*/
public static Class<?> forName(String className) throws ClassNotFoundException {
return forName(className, true, VMStack.getCallingClassLoader());
} /**
* Returns a {@code Class} object which represents the class with the
* specified name. The name should be the name of a class as described in
* the {@link Class class definition}, however {@code Class}es representing
* primitive types can not be found using this method. Security rules will
* be obeyed.
* <p>
* If the class has not been loaded so far, it is being loaded and linked
* first. This is done through either the specified class loader or one of
* its parent class loaders. The caller can also request the class to be
* initialized, which means that a possible static initializer block is
* executed.
*
* @param className
* the name of the non-primitive-type class to find.
* @param initializeBoolean
* indicates whether the class should be initialized.
* @param classLoader
* the class loader to use to load the class.
* @return the named {@code Class} instance.
* @throws ClassNotFoundException
* if the requested class can not be found.
* @throws LinkageError
* if an error occurs during linkage
* @throws ExceptionInInitializerError
* if an exception occurs during static initialization of a
* class.
*/
public static Class<?> forName(String className, boolean initializeBoolean,
ClassLoader classLoader) throws ClassNotFoundException { if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
// Catch an Exception thrown by the underlying native code. It wraps
// up everything inside a ClassNotFoundException, even if e.g. an
// Error occurred during initialization. This as a workaround for
// an ExceptionInInitilaizerError that's also wrapped. It is actually
// expected to be thrown. Maybe the same goes for other errors.
// Not wrapping up all the errors will break android though.
Class<?> result;
try {
result = classForName(className, initializeBoolean,
classLoader);
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof ExceptionInInitializerError) {
throw (ExceptionInInitializerError) cause;
}
throw e;
}
return result;
} /*
* Returns a class by name without any security checks.
*
* @param className The name of the non-primitive type class to find
* @param initializeBoolean A boolean indicating whether the class should be
* initialized
* @param classLoader The class loader to use to load the class
* @return the named class.
* @throws ClassNotFoundException If the class could not be found
*/
static native Class<?> classForName(String className, boolean initializeBoolean,
ClassLoader classLoader) throws ClassNotFoundException; /**
* Returns an array containing {@code Class} objects for all public classes
* and interfaces that are members of this class. This includes public
* members inherited from super classes and interfaces. If there are no such
* class members or if this object represents a primitive type then an array
* of length 0 is returned.
*
* @return the public class members of the class represented by this object.
*/
public Class<?>[] getClasses() {
return getFullListOfClasses(true);
} @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
} A annotation = getDeclaredAnnotation(annotationType);
if (annotation != null) {
return annotation;
} if (annotationType.isAnnotationPresent(Inherited.class)) {
for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
annotation = sup.getDeclaredAnnotation(annotationType);
if (annotation != null) {
return annotation;
}
}
} return null;
} /**
* Returns all the annotations of this class. If there are no annotations
* then an empty array is returned.
*
* @return a copy of the array containing this class' annotations.
* @see #getDeclaredAnnotations()
*/
public Annotation[] getAnnotations() {
/*
* We need to get the annotations declared on this class, plus the
* annotations from superclasses that have the "@Inherited" annotation
* set. We create a temporary map to use while we accumulate the
* annotations and convert it to an array at the end.
*
* It's possible to have duplicates when annotations are inherited.
* We use a Map to filter those out.
*
* HashMap might be overkill here.
*/
HashMap<Class, Annotation> map = new HashMap<Class, Annotation>();
Annotation[] declaredAnnotations = getDeclaredAnnotations(); for (int i = declaredAnnotations.length-1; i >= 0; --i) {
map.put(declaredAnnotations[i].annotationType(), declaredAnnotations[i]);
}
for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
declaredAnnotations = sup.getDeclaredAnnotations();
for (int i = declaredAnnotations.length-1; i >= 0; --i) {
Class<?> clazz = declaredAnnotations[i].annotationType();
if (!map.containsKey(clazz) && clazz.isAnnotationPresent(Inherited.class)) {
map.put(clazz, declaredAnnotations[i]);
}
}
} /* convert annotation values from HashMap to array */
Collection<Annotation> coll = map.values();
return coll.toArray(new Annotation[coll.size()]);
} /**
* Returns the canonical name of this class. If this class does not have a
* canonical name as defined in the Java Language Specification, then the
* method returns {@code null}.
*
* @return this class' canonical name, or {@code null} if it does not have a
* canonical name.
*/
public String getCanonicalName() {
if (isLocalClass() || isAnonymousClass())
return null; if (isArray()) {
/*
* The canonical name of an array type depends on the (existence of)
* the component type's canonical name.
*/
String name = getComponentType().getCanonicalName();
if (name != null) {
return name + "[]";
}
} else if (isMemberClass()) {
/*
* The canonical name of an inner class depends on the (existence
* of) the declaring class' canonical name.
*/
String name = getDeclaringClass().getCanonicalName();
if (name != null) {
return name + "." + getSimpleName();
}
} else {
/*
* The canonical name of a top-level class or primitive type is
* equal to the fully qualified name.
*/
return getName();
} /*
* Other classes don't have a canonical name.
*/
return null;
} /**
* Returns the class loader which was used to load the class represented by
* this {@code Class}. Implementations are free to return {@code null} for
* classes that were loaded by the bootstrap class loader. The Android
* reference implementation, though, returns a reference to an actual
* representation of the bootstrap class loader.
*
* @return the class loader for the represented class.
* @see ClassLoader
*/
public ClassLoader getClassLoader() {
if (this.isPrimitive()) {
return null;
} ClassLoader loader = getClassLoaderImpl();
if (loader == null) {
loader = BootClassLoader.getInstance();
}
return loader;
} /**
* This must be provided by the VM vendor, as it is used by other provided
* class implementations in this package. Outside of this class, it is used
* by SecurityManager.classLoaderDepth(),
* currentClassLoader() and currentLoadedClass(). Return the ClassLoader for
* this Class without doing any security checks. The bootstrap ClassLoader
* is returned, unlike getClassLoader() which returns null in place of the
* bootstrap ClassLoader.
*
* @return the ClassLoader
*/
ClassLoader getClassLoaderImpl() {
ClassLoader loader = getClassLoader(this);
return loader == null ? BootClassLoader.getInstance() : loader;
} /*
* Returns the defining class loader for the given class.
*
* @param clazz the class the class loader of which we want
* @return the class loader
*/
private static native ClassLoader getClassLoader(Class<?> clazz); /**
* Returns a {@code Class} object which represents the component type if
* this class represents an array type. Returns {@code null} if this class
* does not represent an array type. The component type of an array type is
* the type of the elements of the array.
*
* @return the component type of this class.
*/
public native Class<?> getComponentType(); /**
* Returns a {@code Constructor} object which represents the public
* constructor matching the specified parameter types.
*
* @param parameterTypes
* the parameter types of the requested constructor.
* {@code (Class[]) null} is equivalent to the empty array.
* @return the constructor described by {@code parameterTypes}.
* @throws NoSuchMethodException
* if the constructor can not be found.
* @see #getDeclaredConstructor(Class[])
*/
@SuppressWarnings("unchecked")
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException {
return (Constructor) getConstructorOrMethod("<init>", false, true, parameterTypes);
} /**
* Returns a constructor or method with the specified name.
*
* @param name the method name, or "<init>" to return a constructor.
* @param recursive true to search supertypes.
*/
private Member getConstructorOrMethod(String name, boolean recursive,
boolean publicOnly, Class<?>[] parameterTypes) throws NoSuchMethodException {
if (recursive && !publicOnly) {
throw new AssertionError(); // can't lookup non-public members recursively
}
if (name == null) {
throw new NullPointerException("name == null");
}
if (parameterTypes == null) {
parameterTypes = EmptyArray.CLASS;
}
for (Class<?> c : parameterTypes) {
if (c == null) {
throw new NoSuchMethodException("parameter type is null");
}
}
Member result = recursive
? getPublicConstructorOrMethodRecursive(name, parameterTypes)
: Class.getDeclaredConstructorOrMethod(this, name, parameterTypes);
if (result == null || publicOnly && (result.getModifiers() & Modifier.PUBLIC) == 0) {
throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
}
return result;
} private Member getPublicConstructorOrMethodRecursive(String name, Class<?>[] parameterTypes) {
// search superclasses
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
Member result = Class.getDeclaredConstructorOrMethod(c, name, parameterTypes);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
} // search implemented interfaces
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
for (Class<?> ifc : c.getInterfaces()) {
Member result = ifc.getPublicConstructorOrMethodRecursive(name, parameterTypes);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
}
} return null;
} /**
* Returns an array containing {@code Constructor} objects for all public
* constructors for the class represented by this {@code Class}. If there
* are no public constructors or if this {@code Class} represents an array
* class, a primitive type or void then an empty array is returned.
*
* @return an array with the public constructors of the class represented by
* this {@code Class}.
* @see #getDeclaredConstructors()
*/
public Constructor<?>[] getConstructors() {
return getDeclaredConstructors(this, true);
} /**
* Returns the annotations that are directly defined on the class
* represented by this {@code Class}. Annotations that are inherited are not
* included in the result. If there are no annotations at all, an empty
* array is returned.
*
* @return a copy of the array containing the annotations defined for the
* class that this {@code Class} represents.
* @see #getAnnotations()
*/
native public Annotation[] getDeclaredAnnotations(); /**
* Returns the annotation if it exists.
*/
native private <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass); /**
* Returns true if the annotation exists.
*/
native private boolean isDeclaredAnnotationPresent(Class<? extends Annotation> annotationClass); /**
* Returns an array containing {@code Class} objects for all classes and
* interfaces that are declared as members of the class which this {@code
* Class} represents. If there are no classes or interfaces declared or if
* this class represents an array class, a primitive type or void, then an
* empty array is returned.
*
* @return an array with {@code Class} objects for all the classes and
* interfaces that are used in member declarations.
*/
public Class<?>[] getDeclaredClasses() {
return getDeclaredClasses(this, false);
} /*
* Returns the list of member classes without performing any security checks
* first. This includes the member classes inherited from superclasses. If no
* member classes exist at all, an empty array is returned.
*
* @param publicOnly reflects whether we want only public members or all of them
* @return the list of classes
*/
private Class<?>[] getFullListOfClasses(boolean publicOnly) {
Class<?>[] result = getDeclaredClasses(this, publicOnly); // Traverse all superclasses
Class<?> clazz = this.getSuperclass();
while (clazz != null) {
Class<?>[] temp = getDeclaredClasses(clazz, publicOnly);
if (temp.length != 0) {
result = arraycopy(new Class[result.length + temp.length], result, temp);
} clazz = clazz.getSuperclass();
} return result;
} /*
* Returns the list of member classes of the given class. No security checks
* are performed. If no members exist, an empty array is returned.
*
* @param clazz the class the members of which we want
* @param publicOnly reflects whether we want only public member or all of them
* @return the class' class members
*/
private static native Class<?>[] getDeclaredClasses(Class<?> clazz, boolean publicOnly); /**
* Returns a {@code Constructor} object which represents the constructor
* matching the specified parameter types that is declared by the class
* represented by this {@code Class}.
*
* @param parameterTypes
* the parameter types of the requested constructor.
* {@code (Class[]) null} is equivalent to the empty array.
* @return the constructor described by {@code parameterTypes}.
* @throws NoSuchMethodException
* if the requested constructor can not be found.
* @see #getConstructor(Class[])
*/
@SuppressWarnings("unchecked")
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException {
return (Constructor) getConstructorOrMethod("<init>", false, false, parameterTypes);
} /**
* Returns an array containing {@code Constructor} objects for all
* constructors declared in the class represented by this {@code Class}. If
* there are no constructors or if this {@code Class} represents an array
* class, a primitive type or void then an empty array is returned.
*
* @return an array with the constructors declared in the class represented
* by this {@code Class}.
* @see #getConstructors()
*/
public Constructor<?>[] getDeclaredConstructors() {
return getDeclaredConstructors(this, false);
} /*
* Returns the list of constructors without performing any security checks
* first. If no constructors exist, an empty array is returned.
*
* @param clazz the class of interest
* @param publicOnly reflects whether we want only public constructors or all of them
* @return the list of constructors
*/
private static native <T> Constructor<T>[] getDeclaredConstructors(
Class<T> clazz, boolean publicOnly); /**
* Returns a {@code Field} object for the field with the specified name
* which is declared in the class represented by this {@code Class}.
*
* @param name the name of the requested field.
* @return the requested field in the class represented by this class.
* @throws NoSuchFieldException if the requested field can not be found.
* @see #getField(String)
*/
public Field getDeclaredField(String name) throws NoSuchFieldException {
if (name == null) {
throw new NullPointerException("name == null");
}
Field result = getDeclaredField(this, name);
if (result == null) {
throw new NoSuchFieldException(name);
}
return result;
} /**
* Returns an array containing {@code Field} objects for all fields declared
* in the class represented by this {@code Class}. If there are no fields or
* if this {@code Class} represents an array class, a primitive type or void
* then an empty array is returned.
*
* @return an array with the fields declared in the class represented by
* this class.
* @see #getFields()
*/
public Field[] getDeclaredFields() {
return getDeclaredFields(this, false);
} /*
* Returns the list of fields without performing any security checks
* first. If no fields exist at all, an empty array is returned.
*
* @param clazz the class of interest
* @param publicOnly reflects whether we want only public fields or all of them
* @return the list of fields
*/
static native Field[] getDeclaredFields(Class<?> clazz, boolean publicOnly); /**
* Returns the field if it is defined by {@code clazz}; null otherwise. This
* may return a non-public member.
*/
static native Field getDeclaredField(Class<?> clazz, String name); /**
* Returns a {@code Method} object which represents the method matching the
* specified name and parameter types that is declared by the class
* represented by this {@code Class}.
*
* @param name
* the requested method's name.
* @param parameterTypes
* the parameter types of the requested method.
* {@code (Class[]) null} is equivalent to the empty array.
* @return the method described by {@code name} and {@code parameterTypes}.
* @throws NoSuchMethodException
* if the requested constructor can not be found.
* @throws NullPointerException
* if {@code name} is {@code null}.
* @see #getMethod(String, Class[])
*/
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException {
Member member = getConstructorOrMethod(name, false, false, parameterTypes);
if (member instanceof Constructor) {
throw new NoSuchMethodException(name);
}
return (Method) member;
} /**
* Returns an array containing {@code Method} objects for all methods
* declared in the class represented by this {@code Class}. If there are no
* methods or if this {@code Class} represents an array class, a primitive
* type or void then an empty array is returned.
*
* @return an array with the methods declared in the class represented by
* this {@code Class}.
* @see #getMethods()
*/
public Method[] getDeclaredMethods() {
return getDeclaredMethods(this, false);
} /**
* Returns the list of methods without performing any security checks
* first. If no methods exist, an empty array is returned.
*/
static native Method[] getDeclaredMethods(Class<?> clazz, boolean publicOnly); /**
* Returns the constructor or method if it is defined by {@code clazz}; null
* otherwise. This may return a non-public member.
*
* @param name the method name, or "<init>" to get a constructor.
*/
static native Member getDeclaredConstructorOrMethod(Class clazz, String name, Class[] args); /**
* Returns the declaring {@code Class} of this {@code Class}. Returns
* {@code null} if the class is not a member of another class or if this
* {@code Class} represents an array class, a primitive type or void.
*
* @return the declaring {@code Class} or {@code null}.
*/
native public Class<?> getDeclaringClass(); /**
* Returns the enclosing {@code Class} of this {@code Class}. If there is no
* enclosing class the method returns {@code null}.
*
* @return the enclosing {@code Class} or {@code null}.
*/
native public Class<?> getEnclosingClass(); /**
* Gets the enclosing {@code Constructor} of this {@code Class}, if it is an
* anonymous or local/automatic class; otherwise {@code null}.
*
* @return the enclosing {@code Constructor} instance or {@code null}.
*/
native public Constructor<?> getEnclosingConstructor(); /**
* Gets the enclosing {@code Method} of this {@code Class}, if it is an
* anonymous or local/automatic class; otherwise {@code null}.
*
* @return the enclosing {@code Method} instance or {@code null}.
*/
native public Method getEnclosingMethod(); /**
* Gets the {@code enum} constants associated with this {@code Class}.
* Returns {@code null} if this {@code Class} does not represent an {@code
* enum} type.
*
* @return an array with the {@code enum} constants or {@code null}.
*/
@SuppressWarnings("unchecked") // we only cast after confirming that this class is an enum
public T[] getEnumConstants() {
if (!isEnum()) {
return null;
}
return (T[]) Enum.getSharedConstants((Class) this).clone();
} /**
* Returns a {@code Field} object which represents the public field with the
* specified name. This method first searches the class C represented by
* this {@code Class}, then the interfaces implemented by C and finally the
* superclasses of C.
*
* @param name
* the name of the requested field.
* @return the public field specified by {@code name}.
* @throws NoSuchFieldException
* if the field can not be found.
* @see #getDeclaredField(String)
*/
public Field getField(String name) throws NoSuchFieldException {
if (name == null) {
throw new NullPointerException("name == null");
}
Field result = getPublicFieldRecursive(name);
if (result == null) {
throw new NoSuchFieldException(name);
}
return result;
} private Field getPublicFieldRecursive(String name) {
// search superclasses
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
Field result = Class.getDeclaredField(c, name);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
} // search implemented interfaces
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
for (Class<?> ifc : c.getInterfaces()) {
Field result = ifc.getPublicFieldRecursive(name);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
}
} return null;
} /**
* Returns an array containing {@code Field} objects for all public fields
* for the class C represented by this {@code Class}. Fields may be declared
* in C, the interfaces it implements or in the superclasses of C. The
* elements in the returned array are in no particular order.
*
* <p>If there are no public fields or if this class represents an array class,
* a primitive type or {@code void} then an empty array is returned.
*
* @return an array with the public fields of the class represented by this
* {@code Class}.
* @see #getDeclaredFields()
*/
public Field[] getFields() {
List<Field> fields = new ArrayList<Field>();
getPublicFieldsRecursive(fields); /*
* The result may include duplicates when clazz implements an interface
* through multiple paths. Remove those duplicates.
*/
CollectionUtils.removeDuplicates(fields, Field.ORDER_BY_NAME_AND_DECLARING_CLASS);
return fields.toArray(new Field[fields.size()]);
} /**
* Populates {@code result} with public fields defined by this class, its
* superclasses, and all implemented interfaces.
*/
private void getPublicFieldsRecursive(List<Field> result) {
// search superclasses
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
for (Field field : Class.getDeclaredFields(c, true)) {
result.add(field);
}
} // search implemented interfaces
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
for (Class<?> ifc : c.getInterfaces()) {
ifc.getPublicFieldsRecursive(result);
}
}
} /**
* Gets the {@link Type}s of the interfaces that this {@code Class} directly
* implements. If the {@code Class} represents a primitive type or {@code
* void} then an empty array is returned.
*
* @return an array of {@link Type} instances directly implemented by the
* class represented by this {@code class}.
*/
public Type[] getGenericInterfaces() {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, getSignatureAttribute());
return Types.getClonedTypeArray(parser.interfaceTypes);
} /**
* Gets the {@code Type} that represents the superclass of this {@code
* class}.
*
* @return an instance of {@code Type} representing the superclass.
*/
public Type getGenericSuperclass() {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, getSignatureAttribute());
return Types.getType(parser.superclassType);
} /**
* Returns an array of {@code Class} objects that match the interfaces
* specified in the {@code implements} declaration of the class represented
* by this {@code Class}. The order of the elements in the array is
* identical to the order in the original class declaration. If the class
* does not implement any interfaces, an empty array is returned.
*
* @return an array with the interfaces of the class represented by this
* class.
*/
public native Class<?>[] getInterfaces(); /**
* Returns a {@code Method} object which represents the public method with
* the specified name and parameter types. This method first searches the
* class C represented by this {@code Class}, then the superclasses of C and
* finally the interfaces implemented by C and finally the superclasses of C
* for a method with matching name.
*
* @param name
* the requested method's name.
* @param parameterTypes
* the parameter types of the requested method.
* {@code (Class[]) null} is equivalent to the empty array.
* @return the public field specified by {@code name}.
* @throws NoSuchMethodException
* if the method can not be found.
* @see #getDeclaredMethod(String, Class[])
*/
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
Member member = getConstructorOrMethod(name, true, true, parameterTypes);
if (member instanceof Constructor) {
throw new NoSuchMethodException(name);
}
return (Method) member;
} /**
* Returns an array containing {@code Method} objects for all public methods
* for the class C represented by this {@code Class}. Methods may be
* declared in C, the interfaces it implements or in the superclasses of C.
* The elements in the returned array are in no particular order.
* <p>
* If there are no public methods or if this {@code Class} represents a
* primitive type or {@code void} then an empty array is returned.
* </p>
*
* @return an array with the methods of the class represented by this
* {@code Class}.
* @see #getDeclaredMethods()
*/
public Method[] getMethods() {
List<Method> methods = new ArrayList<Method>();
getPublicMethodsRecursive(methods); /*
* Remove methods defined by multiple types, preferring to keep methods
* declared by derived types.
*/
CollectionUtils.removeDuplicates(methods, Method.ORDER_BY_SIGNATURE);
return methods.toArray(new Method[methods.size()]);
} /**
* Populates {@code result} with public methods defined by {@code clazz}, its
* superclasses, and all implemented interfaces, including overridden methods.
*/
private void getPublicMethodsRecursive(List<Method> result) {
// search superclasses
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
for (Method method : Class.getDeclaredMethods(c, true)) {
result.add(method);
}
} // search implemented interfaces
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
for (Class<?> ifc : c.getInterfaces()) {
ifc.getPublicMethodsRecursive(result);
}
}
} /**
* Returns an integer that represents the modifiers of the class represented
* by this {@code Class}. The returned value is a combination of bits
* defined by constants in the {@link Modifier} class.
*
* @return the modifiers of the class represented by this {@code Class}.
*/
public int getModifiers() {
return getModifiers(this, false);
} /*
* Return the modifiers for the given class.
*
* @param clazz the class of interest
* @ignoreInnerClassesAttrib determines whether we look for and use the
* flags from an "inner class" attribute
*/
private static native int getModifiers(Class<?> clazz, boolean ignoreInnerClassesAttrib); /**
* Returns the name of the class represented by this {@code Class}. For a
* description of the format which is used, see the class definition of
* {@link Class}.
*
* @return the name of the class represented by this {@code Class}.
*/
public String getName() {
String result = name;
return (result == null) ? (name = getNameNative()) : result;
} private native String getNameNative(); /**
* Returns the simple name of the class represented by this {@code Class} as
* defined in the source code. If there is no name (that is, the class is
* anonymous) then an empty string is returned. If the receiver is an array
* then the name of the underlying type with square braces appended (for
* example {@code "Integer[]"}) is returned.
*
* @return the simple name of the class represented by this {@code Class}.
*/
public String getSimpleName() {
if (isArray()) {
return getComponentType().getSimpleName() + "[]";
} String name = getName(); if (isAnonymousClass()) {
return "";
} if (isMemberClass() || isLocalClass()) {
return getInnerClassName();
} int dot = name.lastIndexOf('.');
if (dot != -1) {
return name.substring(dot + 1);
} return name;
} /*
* Returns the simple name of a member or local class, or null otherwise.
*
* @return The name.
*/
private native String getInnerClassName(); /**
* Returns null.
*/
public ProtectionDomain getProtectionDomain() {
return null;
} /**
* Returns the URL of the resource specified by {@code resName}. The mapping
* between the resource name and the URL is managed by the class' class
* loader.
*
* @param resName
* the name of the resource.
* @return the requested resource's {@code URL} object or {@code null} if
* the resource can not be found.
* @see ClassLoader
*/
public URL getResource(String resName) {
// Get absolute resource name, but without the leading slash
if (resName.startsWith("/")) {
resName = resName.substring(1);
} else {
String pkg = getName();
int dot = pkg.lastIndexOf('.');
if (dot != -1) {
pkg = pkg.substring(0, dot).replace('.', '/');
} else {
pkg = "";
} resName = pkg + "/" + resName;
} // Delegate to proper class loader
ClassLoader loader = getClassLoader();
if (loader != null) {
return loader.getResource(resName);
} else {
return ClassLoader.getSystemResource(resName);
}
} /**
* Returns a read-only stream for the contents of the resource specified by
* {@code resName}. The mapping between the resource name and the stream is
* managed by the class' class loader.
*
* @param resName
* the name of the resource.
* @return a stream for the requested resource or {@code null} if no
* resource with the specified name can be found.
* @see ClassLoader
*/
public InputStream getResourceAsStream(String resName) {
// Get absolute resource name, but without the leading slash
if (resName.startsWith("/")) {
resName = resName.substring(1);
} else {
String pkg = getName();
int dot = pkg.lastIndexOf('.');
if (dot != -1) {
pkg = pkg.substring(0, dot).replace('.', '/');
} else {
pkg = "";
} resName = pkg + "/" + resName;
} // Delegate to proper class loader
ClassLoader loader = getClassLoader();
if (loader != null) {
return loader.getResourceAsStream(resName);
} else {
return ClassLoader.getSystemResourceAsStream(resName);
}
} /**
* Returns null. (On Android, a {@code ClassLoader} can load classes from multiple dex files.
* All classes from any given dex file will have the same signers, but different dex
* files may have different signers. This does not fit well with the original
* {@code ClassLoader}-based model of {@code getSigners}.)
*
* @return null.
*/
public Object[] getSigners() {
// See http://code.google.com/p/android/issues/detail?id=1766.
return null;
} /**
* Returns the {@code Class} object which represents the superclass of the
* class represented by this {@code Class}. If this {@code Class} represents
* the {@code Object} class, a primitive type, an interface or void then the
* method returns {@code null}. If this {@code Class} represents an array
* class then the {@code Object} class is returned.
*
* @return the superclass of the class represented by this {@code Class}.
*/
public native Class<? super T> getSuperclass(); /**
* Returns an array containing {@code TypeVariable} objects for type
* variables declared by the generic class represented by this {@code
* Class}. Returns an empty array if the class is not generic.
*
* @return an array with the type variables of the class represented by this
* class.
*/
@SuppressWarnings("unchecked")
public synchronized TypeVariable<Class<T>>[] getTypeParameters() {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, getSignatureAttribute());
return parser.formalTypeParameters.clone();
} /**
* Indicates whether this {@code Class} represents an annotation class.
*
* @return {@code true} if this {@code Class} represents an annotation
* class; {@code false} otherwise.
*/
public boolean isAnnotation() {
final int ACC_ANNOTATION = 0x2000; // not public in reflect.Modifiers
int mod = getModifiers(this, true);
return (mod & ACC_ANNOTATION) != 0;
} @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
} if (isDeclaredAnnotationPresent(annotationType)) {
return true;
} if (annotationType.isDeclaredAnnotationPresent(Inherited.class)) {
for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
if (sup.isDeclaredAnnotationPresent(annotationType)) {
return true;
}
}
} return false;
} /**
* Indicates whether the class represented by this {@code Class} is
* anonymously declared.
*
* @return {@code true} if the class represented by this {@code Class} is
* anonymous; {@code false} otherwise.
*/
native public boolean isAnonymousClass(); /**
* Indicates whether the class represented by this {@code Class} is an array
* class.
*
* @return {@code true} if the class represented by this {@code Class} is an
* array class; {@code false} otherwise.
*/
public boolean isArray() {
return getComponentType() != null;
} /**
* Indicates whether the specified class type can be converted to the class
* represented by this {@code Class}. Conversion may be done via an identity
* conversion or a widening reference conversion (if either the receiver or
* the argument represent primitive types, only the identity conversion
* applies).
*
* @param cls
* the class to check.
* @return {@code true} if {@code cls} can be converted to the class
* represented by this {@code Class}; {@code false} otherwise.
* @throws NullPointerException
* if {@code cls} is {@code null}.
*/
public native boolean isAssignableFrom(Class<?> cls); /**
* Indicates whether the class represented by this {@code Class} is an
* {@code enum}.
*
* @return {@code true} if the class represented by this {@code Class} is an
* {@code enum}; {@code false} otherwise.
*/
public boolean isEnum() {
return ((getModifiers() & 0x4000) != 0) && (getSuperclass() == Enum.class);
} /**
* Indicates whether the specified object can be cast to the class
* represented by this {@code Class}. This is the runtime version of the
* {@code instanceof} operator.
*
* @param object
* the object to check.
* @return {@code true} if {@code object} can be cast to the type
* represented by this {@code Class}; {@code false} if {@code
* object} is {@code null} or cannot be cast.
*/
public native boolean isInstance(Object object); /**
* Indicates whether this {@code Class} represents an interface.
*
* @return {@code true} if this {@code Class} represents an interface;
* {@code false} otherwise.
*/
public native boolean isInterface(); /**
* Indicates whether the class represented by this {@code Class} is defined
* locally.
*
* @return {@code true} if the class represented by this {@code Class} is
* defined locally; {@code false} otherwise.
*/
public boolean isLocalClass() {
boolean enclosed = (getEnclosingMethod() != null ||
getEnclosingConstructor() != null);
return enclosed && !isAnonymousClass();
} /**
* Indicates whether the class represented by this {@code Class} is a member
* class.
*
* @return {@code true} if the class represented by this {@code Class} is a
* member class; {@code false} otherwise.
*/
public boolean isMemberClass() {
return getDeclaringClass() != null;
} /**
* Indicates whether this {@code Class} represents a primitive type.
*
* @return {@code true} if this {@code Class} represents a primitive type;
* {@code false} otherwise.
*/
public native boolean isPrimitive(); /**
* Indicates whether this {@code Class} represents a synthetic type.
*
* @return {@code true} if this {@code Class} represents a synthetic type;
* {@code false} otherwise.
*/
public boolean isSynthetic() {
final int ACC_SYNTHETIC = 0x1000; // not public in reflect.Modifiers
int mod = getModifiers(this, true);
return (mod & ACC_SYNTHETIC) != 0;
} /**
* Returns a new instance of the class represented by this {@code Class},
* created by invoking the default (that is, zero-argument) constructor. If
* there is no such constructor, or if the creation fails (either because of
* a lack of available memory or because an exception is thrown by the
* constructor), an {@code InstantiationException} is thrown. If the default
* constructor exists but is not accessible from the context where this
* method is invoked, an {@code IllegalAccessException} is thrown.
*
* @return a new instance of the class represented by this {@code Class}.
* @throws IllegalAccessException
* if the default constructor is not visible.
* @throws InstantiationException
* if the instance can not be created.
*/
public T newInstance() throws InstantiationException, IllegalAccessException {
return newInstanceImpl();
} private native T newInstanceImpl() throws IllegalAccessException, InstantiationException; @Override
public String toString() {
if (isPrimitive()) {
return getSimpleName();
} else {
return (isInterface() ? "interface " : "class ") + getName();
}
} /**
* Returns the {@code Package} of which the class represented by this
* {@code Class} is a member. Returns {@code null} if no {@code Package}
* object was created by the class loader of the class.
*
* @return Package the {@code Package} of which this {@code Class} is a
* member or {@code null}.
*/
public Package getPackage() {
// TODO This might be a hack, but the VM doesn't have the necessary info.
ClassLoader loader = getClassLoader();
if (loader != null) {
String name = getName();
int dot = name.lastIndexOf('.');
return (dot != -1 ? loader.getPackage(name.substring(0, dot)) : null);
}
return null;
} /**
* Returns the assertion status for the class represented by this {@code
* Class}. Assertion is enabled / disabled based on the class loader,
* package or class default at runtime.
*
* @return the assertion status for the class represented by this {@code
* Class}.
*/
public native boolean desiredAssertionStatus(); /**
* Casts this {@code Class} to represent a subclass of the specified class.
* If successful, this {@code Class} is returned; otherwise a {@code
* ClassCastException} is thrown.
*
* @param clazz
* the required type.
* @return this {@code Class} cast as a subclass of the given type.
* @throws ClassCastException
* if this {@code Class} cannot be cast to the specified type.
*/
@SuppressWarnings("unchecked")
public <U> Class<? extends U> asSubclass(Class<U> clazz) {
if (clazz.isAssignableFrom(this)) {
return (Class<? extends U>)this;
}
String actualClassName = this.getName();
String desiredClassName = clazz.getName();
throw new ClassCastException(actualClassName + " cannot be cast to " + desiredClassName);
} /**
* Casts the specified object to the type represented by this {@code Class}.
* If the object is {@code null} then the result is also {@code null}.
*
* @param obj
* the object to cast.
* @return the object that has been cast.
* @throws ClassCastException
* if the object cannot be cast to the specified type.
*/
@SuppressWarnings("unchecked")
public T cast(Object obj) {
if (obj == null) {
return null;
} else if (this.isInstance(obj)) {
return (T)obj;
}
String actualClassName = obj.getClass().getName();
String desiredClassName = this.getName();
throw new ClassCastException(actualClassName + " cannot be cast to " + desiredClassName);
} /**
* Copies two arrays into one. Assumes that the destination array is large
* enough.
*
* @param result the destination array
* @param head the first source array
* @param tail the second source array
* @return the destination array, that is, result
*/
private static <T extends Object> T[] arraycopy(T[] result, T[] head, T[] tail) {
System.arraycopy(head, 0, result, 0, head.length);
System.arraycopy(tail, 0, result, head.length, tail.length);
return result;
}
}
Constructor
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang.reflect; import java.lang.annotation.Annotation;
import libcore.util.EmptyArray;
import org.apache.harmony.kernel.vm.StringUtils;
import org.apache.harmony.luni.lang.reflect.GenericSignatureParser;
import org.apache.harmony.luni.lang.reflect.ListOfTypes;
import org.apache.harmony.luni.lang.reflect.Types; /**
* This class represents a constructor. Information about the constructor can be
* accessed, and the constructor can be invoked dynamically.
*
* @param <T> the class that declares this constructor
*/
public final class Constructor<T> extends AccessibleObject implements GenericDeclaration,
Member { Class<T> declaringClass; Class<?>[] parameterTypes; Class<?>[] exceptionTypes; ListOfTypes genericExceptionTypes;
ListOfTypes genericParameterTypes;
TypeVariable<Constructor<T>>[] formalTypeParameters;
private volatile boolean genericTypesAreInitialized = false; private synchronized void initGenericTypes() {
if (!genericTypesAreInitialized) {
String signatureAttribute = getSignatureAttribute();
GenericSignatureParser parser = new GenericSignatureParser(
declaringClass.getClassLoader());
parser.parseForConstructor(this, signatureAttribute, exceptionTypes);
formalTypeParameters = parser.formalTypeParameters;
genericParameterTypes = parser.parameterTypes;
genericExceptionTypes = parser.exceptionTypes;
genericTypesAreInitialized = true;
}
} int slot; /**
* Prevent this class from being instantiated.
*/
private Constructor(){
//do nothing
} /**
* Creates an instance of the class. Only called from native code, thus
* private.
*
* @param declaringClass
* the class this constructor object belongs to
* @param ptypes
* the parameter types of the constructor
* @param extypes
* the exception types of the constructor
* @param slot
* the slot of the constructor inside the VM class structure
*/
private Constructor (Class<T> declaringClass, Class<?>[] ptypes, Class<?>[] extypes, int slot){
this.declaringClass = declaringClass;
this.parameterTypes = ptypes;
this.exceptionTypes = extypes; // may be null
this.slot = slot;
} @Override /*package*/ String getSignatureAttribute() {
Object[] annotation = Method.getSignatureAnnotation(declaringClass, slot); if (annotation == null) {
return null;
} return StringUtils.combineStrings(annotation);
} public TypeVariable<Constructor<T>>[] getTypeParameters() {
initGenericTypes();
return formalTypeParameters.clone();
} /**
* Returns the string representation of the constructor's declaration,
* including the type parameters.
*
* @return the string representation of the constructor's declaration
*/
public String toGenericString() {
StringBuilder sb = new StringBuilder(80);
initGenericTypes();
// append modifiers if any
int modifier = getModifiers();
if (modifier != 0) {
sb.append(Modifier.toString(modifier & ~Modifier.VARARGS)).append(' ');
}
// append type parameters
if (formalTypeParameters != null && formalTypeParameters.length > 0) {
sb.append('<');
for (int i = 0; i < formalTypeParameters.length; i++) {
appendGenericType(sb, formalTypeParameters[i]);
if (i < formalTypeParameters.length - 1) {
sb.append(",");
}
}
sb.append("> ");
}
// append constructor name
appendArrayType(sb, getDeclaringClass());
// append parameters
sb.append('(');
appendArrayGenericType(sb,
Types.getClonedTypeArray(genericParameterTypes));
sb.append(')');
// append exceptions if any
Type[] genericExceptionTypeArray =
Types.getClonedTypeArray(genericExceptionTypes);
if (genericExceptionTypeArray.length > 0) {
sb.append(" throws ");
appendArrayGenericType(sb, genericExceptionTypeArray);
}
return sb.toString();
} /**
* Returns the generic parameter types as an array of {@code Type}
* instances, in declaration order. If this constructor has no generic
* parameters, an empty array is returned.
*
* @return the parameter types
*
* @throws GenericSignatureFormatError
* if the generic constructor signature is invalid
* @throws TypeNotPresentException
* if any parameter type points to a missing type
* @throws MalformedParameterizedTypeException
* if any parameter type points to a type that cannot be
* instantiated for some reason
*/
public Type[] getGenericParameterTypes() {
initGenericTypes();
return Types.getClonedTypeArray(genericParameterTypes);
} /**
* Returns the exception types as an array of {@code Type} instances. If
* this constructor has no declared exceptions, an empty array will be
* returned.
*
* @return an array of generic exception types
*
* @throws GenericSignatureFormatError
* if the generic constructor signature is invalid
* @throws TypeNotPresentException
* if any exception type points to a missing type
* @throws MalformedParameterizedTypeException
* if any exception type points to a type that cannot be
* instantiated for some reason
*/
public Type[] getGenericExceptionTypes() {
initGenericTypes();
return Types.getClonedTypeArray(genericExceptionTypes);
} @Override
public Annotation[] getDeclaredAnnotations() {
return Method.getDeclaredAnnotations(declaringClass, slot);
} @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
return Method.getAnnotation(declaringClass, slot, annotationType);
} @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
return Method.isAnnotationPresent(declaringClass, slot, annotationType);
} /**
* Returns an array of arrays that represent the annotations of the formal
* parameters of this constructor. If there are no parameters on this
* constructor, then an empty array is returned. If there are no annotations
* set, then an array of empty arrays is returned.
*
* @return an array of arrays of {@code Annotation} instances
*/
public Annotation[][] getParameterAnnotations() {
Annotation[][] parameterAnnotations
= Method.getParameterAnnotations(declaringClass, slot);
if (parameterAnnotations.length == 0) {
return Method.noAnnotations(parameterTypes.length);
}
return parameterAnnotations;
} /**
* Indicates whether or not this constructor takes a variable number of
* arguments.
*
* @return {@code true} if a vararg is declare, otherwise
* {@code false}
*/
public boolean isVarArgs() {
int mods = Method.getMethodModifiers(declaringClass, slot);
return (mods & Modifier.VARARGS) != 0;
} /**
* Indicates whether or not this constructor is synthetic (artificially
* introduced by the compiler).
*
* @return {@code true} if this constructor is synthetic, {@code false}
* otherwise
*/
public boolean isSynthetic() {
int mods = Method.getMethodModifiers(declaringClass, slot);
return (mods & Modifier.SYNTHETIC) != 0;
} /**
* Indicates whether or not the specified {@code object} is equal to this
* constructor. To be equal, the specified object must be an instance
* of {@code Constructor} with the same declaring class and parameter types
* as this constructor.
*
* @param object
* the object to compare
*
* @return {@code true} if the specified object is equal to this
* constructor, {@code false} otherwise
*
* @see #hashCode
*/
@Override
public boolean equals(Object object) {
return object instanceof Constructor && toString().equals(object.toString());
} /**
* Returns the class that declares this constructor.
*
* @return the declaring class
*/
public Class<T> getDeclaringClass() {
return declaringClass;
} /**
* Returns the exception types as an array of {@code Class} instances. If
* this constructor has no declared exceptions, an empty array will be
* returned.
*
* @return the declared exception classes
*/
public Class<?>[] getExceptionTypes() {
if (exceptionTypes == null) {
return EmptyArray.CLASS;
}
return exceptionTypes.clone();
} /**
* Returns the modifiers for this constructor. The {@link Modifier} class
* should be used to decode the result.
*
* @return the modifiers for this constructor
*
* @see Modifier
*/
public int getModifiers() {
return Method.getMethodModifiers(declaringClass, slot);
} /**
* Returns the name of this constructor.
*
* @return the name of this constructor
*/
public String getName() {
return declaringClass.getName();
} /**
* Returns an array of the {@code Class} objects associated with the
* parameter types of this constructor. If the constructor was declared with
* no parameters, an empty array will be returned.
*
* @return the parameter types
*/
public Class<?>[] getParameterTypes() {
return parameterTypes.clone();
} /**
* Returns the constructor's signature in non-printable form. This is called
* (only) from IO native code and needed for deriving the serialVersionUID
* of the class
*
* @return the constructor's signature
*/
@SuppressWarnings("unused")
private String getSignature() {
StringBuilder result = new StringBuilder(); result.append('(');
for (int i = 0; i < parameterTypes.length; i++) {
result.append(getSignature(parameterTypes[i]));
}
result.append(")V"); return result.toString();
} /**
* Returns an integer hash code for this constructor. Constructors which are
* equal return the same value for this method. The hash code for a
* Constructor is the hash code of the name of the declaring class.
*
* @return the hash code
*
* @see #equals
*/
@Override
public int hashCode() {
return declaringClass.getName().hashCode();
} /**
* Returns a new instance of the declaring class, initialized by dynamically
* invoking the constructor represented by this {@code Constructor} object.
* This reproduces the effect of {@code new declaringClass(arg1, arg2, ... ,
* argN)} This method performs the following:
* <ul>
* <li>A new instance of the declaring class is created. If the declaring
* class cannot be instantiated (i.e. abstract class, an interface, an array
* type, or a primitive type) then an InstantiationException is thrown.</li>
* <li>If this Constructor object is enforcing access control (see
* {@link AccessibleObject}) and this constructor is not accessible from the
* current context, an IllegalAccessException is thrown.</li>
* <li>If the number of arguments passed and the number of parameters do not
* match, an IllegalArgumentException is thrown.</li>
* <li>For each argument passed:
* <ul>
* <li>If the corresponding parameter type is a primitive type, the argument
* is unboxed. If the unboxing fails, an IllegalArgumentException is
* thrown.</li>
* <li>If the resulting argument cannot be converted to the parameter type
* via a widening conversion, an IllegalArgumentException is thrown.</li>
* </ul>
* <li>The constructor represented by this {@code Constructor} object is
* then invoked. If an exception is thrown during the invocation, it is
* caught and wrapped in an InvocationTargetException. This exception is
* then thrown. If the invocation completes normally, the newly initialized
* object is returned.
* </ul>
*
* @param args
* the arguments to the constructor
*
* @return the new, initialized, object
*
* @exception InstantiationException
* if the class cannot be instantiated
* @exception IllegalAccessException
* if this constructor is not accessible
* @exception IllegalArgumentException
* if an incorrect number of arguments are passed, or an
* argument could not be converted by a widening conversion
* @exception InvocationTargetException
* if an exception was thrown by the invoked constructor
*
* @see AccessibleObject
*/
public T newInstance(Object... args) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
return constructNative (args, declaringClass, parameterTypes, slot, flag);
} private native T constructNative(Object[] args, Class<T> declaringClass,
Class<?>[] parameterTypes, int slot,
boolean noAccessCheck) throws InstantiationException, IllegalAccessException,
InvocationTargetException; /**
* Returns a string containing a concise, human-readable description of this
* constructor. The format of the string is:
*
* <ol>
* <li>modifiers (if any)
* <li>declaring class name
* <li>'('
* <li>parameter types, separated by ',' (if any)
* <li>')'
* <li>'throws' plus exception types, separated by ',' (if any)
* </ol>
*
* For example:
* {@code public String(byte[],String) throws UnsupportedEncodingException}
*
* @return a printable representation for this constructor
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder(Modifier.toString(getModifiers())); if (result.length() != 0)
result.append(' ');
result.append(declaringClass.getName());
result.append("(");
result.append(toString(parameterTypes));
result.append(")");
if (exceptionTypes != null && exceptionTypes.length != 0) {
result.append(" throws ");
result.append(toString(exceptionTypes));
} return result.toString();
}
}
Field
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang.reflect; import java.lang.annotation.Annotation;
import java.util.Comparator;
import org.apache.harmony.kernel.vm.StringUtils;
import org.apache.harmony.luni.lang.reflect.GenericSignatureParser;
import org.apache.harmony.luni.lang.reflect.Types; /**
* This class represents a field. Information about the field can be accessed,
* and the field's value can be accessed dynamically.
*/
public final class Field extends AccessibleObject implements Member { /**
* Orders fields by their name and declaring class.
*
* @hide
*/
public static final Comparator<Field> ORDER_BY_NAME_AND_DECLARING_CLASS
= new Comparator<Field>() {
@Override public int compare(Field a, Field b) {
int comparison = a.name.compareTo(b.name);
if (comparison != 0) {
return comparison;
} return a.getDeclaringClass().getName().compareTo(b.getDeclaringClass().getName());
}
}; private Class<?> declaringClass; private Class<?> type; private Type genericType; private volatile boolean genericTypesAreInitialized = false; private String name; private int slot; private static final char TYPE_BOOLEAN = 'Z'; private static final char TYPE_BYTE = 'B'; private static final char TYPE_CHAR = 'C'; private static final char TYPE_SHORT = 'S'; private static final char TYPE_INTEGER = 'I'; private static final char TYPE_FLOAT = 'F'; private static final char TYPE_LONG = 'J'; private static final char TYPE_DOUBLE = 'D'; /**
* Construct a clone of the given instance.
*
* @param orig non-null; the original instance to clone
*/
/*package*/ Field(Field orig) {
this(orig.declaringClass, orig.type, orig.name, orig.slot); // Copy the accessible flag.
if (orig.flag) {
this.flag = true;
}
} private Field(Class<?> declaringClass, Class<?> type, String name, int slot) {
this.declaringClass = declaringClass;
this.type = type;
this.name = name;
this.slot = slot;
} private synchronized void initGenericType() {
if (!genericTypesAreInitialized) {
String signatureAttribute = getSignatureAttribute();
GenericSignatureParser parser = new GenericSignatureParser(
declaringClass.getClassLoader());
parser.parseForField(this.declaringClass, signatureAttribute);
genericType = parser.fieldType;
if (genericType == null) {
genericType = getType();
}
genericTypesAreInitialized = true;
}
} /** {@inheritDoc} */
@Override
/* package */String getSignatureAttribute() {
Object[] annotation = getSignatureAnnotation(declaringClass, slot); if (annotation == null) {
return null;
} return StringUtils.combineStrings(annotation);
} /**
* Get the Signature annotation for this field. Returns null if not found.
*/
native private Object[] getSignatureAnnotation(Class declaringClass, int slot); /**
* Indicates whether or not this field is synthetic.
*
* @return {@code true} if this field is synthetic, {@code false} otherwise
*/
public boolean isSynthetic() {
int flags = getFieldModifiers(declaringClass, slot);
return (flags & Modifier.SYNTHETIC) != 0;
} /**
* Returns the string representation of this field, including the field's
* generic type.
*
* @return the string representation of this field
*/
public String toGenericString() {
StringBuilder sb = new StringBuilder(80);
// append modifiers if any
int modifier = getModifiers();
if (modifier != 0) {
sb.append(Modifier.toString(modifier)).append(' ');
}
// append generic type
appendGenericType(sb, getGenericType());
sb.append(' ');
// append full field name
sb.append(getDeclaringClass().getName()).append('.').append(getName());
return sb.toString();
} /**
* Indicates whether or not this field is an enumeration constant.
*
* @return {@code true} if this field is an enumeration constant, {@code
* false} otherwise
*/
public boolean isEnumConstant() {
int flags = getFieldModifiers(declaringClass, slot);
return (flags & Modifier.ENUM) != 0;
} /**
* Returns the generic type of this field.
*
* @return the generic type
* @throws GenericSignatureFormatError
* if the generic field signature is invalid
* @throws TypeNotPresentException
* if the generic type points to a missing type
* @throws MalformedParameterizedTypeException
* if the generic type points to a type that cannot be
* instantiated for some reason
*/
public Type getGenericType() {
initGenericType();
return Types.getType(genericType);
} @Override public Annotation[] getDeclaredAnnotations() {
return getDeclaredAnnotations(declaringClass, slot);
}
private static native Annotation[] getDeclaredAnnotations(Class declaringClass, int slot); @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
return getAnnotation(declaringClass, slot, annotationType);
}
private static native <A extends Annotation> A getAnnotation(
Class<?> declaringClass, int slot, Class<A> annotationType); @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
return isAnnotationPresent(declaringClass, slot, annotationType);
}
private static native boolean isAnnotationPresent(
Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType); /**
* Indicates whether or not the specified {@code object} is equal to this
* field. To be equal, the specified object must be an instance of
* {@code Field} with the same declaring class, type and name as this field.
*
* @param object
* the object to compare
* @return {@code true} if the specified object is equal to this method,
* {@code false} otherwise
* @see #hashCode
*/
@Override
public boolean equals(Object object) {
return object instanceof Field && toString().equals(object.toString());
} /**
* Returns the value of the field in the specified object. This reproduces
* the effect of {@code object.fieldName}
*
* <p>If the type of this field is a primitive type, the field value is
* automatically boxed.
*
* <p>If this field is static, the object argument is ignored.
* Otherwise, if the object is null, a NullPointerException is thrown. If
* the object is not an instance of the declaring class of the method, an
* IllegalArgumentException is thrown.
*
* <p>If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value, possibly boxed
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public Object get(Object object) throws IllegalAccessException, IllegalArgumentException {
return getField(object, declaringClass, type, slot, flag);
} /**
* Returns the value of the field in the specified object as a {@code
* boolean}. This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public boolean getBoolean(Object object) throws IllegalAccessException,
IllegalArgumentException {
return getZField(object, declaringClass, type, slot, flag, TYPE_BOOLEAN);
} /**
* Returns the value of the field in the specified object as a {@code byte}.
* This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public byte getByte(Object object) throws IllegalAccessException, IllegalArgumentException {
return getBField(object, declaringClass, type, slot, flag, TYPE_BYTE);
} /**
* Returns the value of the field in the specified object as a {@code char}.
* This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public char getChar(Object object) throws IllegalAccessException, IllegalArgumentException {
return getCField(object, declaringClass, type, slot, flag, TYPE_CHAR);
} /**
* Returns the class that declares this field.
*
* @return the declaring class
*/
public Class<?> getDeclaringClass() {
return declaringClass;
} /**
* Returns the value of the field in the specified object as a {@code
* double}. This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public double getDouble(Object object) throws IllegalAccessException, IllegalArgumentException {
return getDField(object, declaringClass, type, slot, flag, TYPE_DOUBLE);
} /**
* Returns the value of the field in the specified object as a {@code float}
* . This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public float getFloat(Object object) throws IllegalAccessException, IllegalArgumentException {
return getFField(object, declaringClass, type, slot, flag, TYPE_FLOAT);
} /**
* Returns the value of the field in the specified object as an {@code int}.
* This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public int getInt(Object object) throws IllegalAccessException, IllegalArgumentException {
return getIField(object, declaringClass, type, slot, flag, TYPE_INTEGER);
} /**
* Returns the value of the field in the specified object as a {@code long}.
* This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public long getLong(Object object) throws IllegalAccessException, IllegalArgumentException {
return getJField(object, declaringClass, type, slot, flag, TYPE_LONG);
} /**
* Returns the modifiers for this field. The {@link Modifier} class should
* be used to decode the result.
*
* @return the modifiers for this field
* @see Modifier
*/
public int getModifiers() {
return getFieldModifiers(declaringClass, slot);
} private native int getFieldModifiers(Class<?> declaringClass, int slot); /**
* Returns the name of this field.
*
* @return the name of this field
*/
public String getName() {
return name;
} /**
* Returns the value of the field in the specified object as a {@code short}
* . This reproduces the effect of {@code object.fieldName}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* @param object
* the object to access
* @return the field value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public short getShort(Object object) throws IllegalAccessException, IllegalArgumentException {
return getSField(object, declaringClass, type, slot, flag, TYPE_SHORT);
} /**
* Returns the constructor's signature in non-printable form. This is called
* (only) from IO native code and needed for deriving the serialVersionUID
* of the class
*
* @return the constructor's signature.
*/
@SuppressWarnings("unused")
private String getSignature() {
return getSignature(type);
} /**
* Return the {@link Class} associated with the type of this field.
*
* @return the type of this field
*/
public Class<?> getType() {
return type;
} /**
* Returns an integer hash code for this field. Objects which are equal
* return the same value for this method.
* <p>
* The hash code for a Field is the exclusive-or combination of the hash
* code of the field's name and the hash code of the name of its declaring
* class.
*
* @return the hash code for this field
* @see #equals
*/
@Override
public int hashCode() {
return name.hashCode() ^ getDeclaringClass().getName().hashCode();
} /**
* Sets the value of the field in the specified object to the value. This
* reproduces the effect of {@code object.fieldName = value}
*
* <p>If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
*
* <p>If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
*
* <p>If the field type is a primitive type, the value is automatically
* unboxed. If the unboxing fails, an IllegalArgumentException is thrown. If
* the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void set(Object object, Object value) throws IllegalAccessException,
IllegalArgumentException {
setField(object, declaringClass, type, slot, flag, value);
} /**
* Sets the value of the field in the specified object to the {@code
* boolean} value. This reproduces the effect of {@code object.fieldName =
* value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setBoolean(Object object, boolean value) throws IllegalAccessException,
IllegalArgumentException {
setZField(object, declaringClass, type, slot, flag, TYPE_BOOLEAN, value);
} /**
* Sets the value of the field in the specified object to the {@code byte}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setByte(Object object, byte value) throws IllegalAccessException,
IllegalArgumentException {
setBField(object, declaringClass, type, slot, flag, TYPE_BYTE, value);
} /**
* Sets the value of the field in the specified object to the {@code char}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setChar(Object object, char value) throws IllegalAccessException,
IllegalArgumentException {
setCField(object, declaringClass, type, slot, flag, TYPE_CHAR, value);
} /**
* Sets the value of the field in the specified object to the {@code double}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setDouble(Object object, double value) throws IllegalAccessException,
IllegalArgumentException {
setDField(object, declaringClass, type, slot, flag, TYPE_DOUBLE, value);
} /**
* Sets the value of the field in the specified object to the {@code float}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setFloat(Object object, float value) throws IllegalAccessException,
IllegalArgumentException {
setFField(object, declaringClass, type, slot, flag, TYPE_FLOAT, value);
} /**
* Set the value of the field in the specified object to the {@code int}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setInt(Object object, int value) throws IllegalAccessException,
IllegalArgumentException {
setIField(object, declaringClass, type, slot, flag, TYPE_INTEGER, value);
} /**
* Sets the value of the field in the specified object to the {@code long}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setLong(Object object, long value) throws IllegalAccessException,
IllegalArgumentException {
setJField(object, declaringClass, type, slot, flag, TYPE_LONG, value);
} /**
* Sets the value of the field in the specified object to the {@code short}
* value. This reproduces the effect of {@code object.fieldName = value}
* <p>
* If this field is static, the object argument is ignored.
* Otherwise, if the object is {@code null}, a NullPointerException is
* thrown. If the object is not an instance of the declaring class of the
* method, an IllegalArgumentException is thrown.
* <p>
* If this Field object is enforcing access control (see AccessibleObject)
* and this field is not accessible from the current context, an
* IllegalAccessException is thrown.
* <p>
* If the value cannot be converted to the field type via a widening
* conversion, an IllegalArgumentException is thrown.
*
* @param object
* the object to access
* @param value
* the new value
* @throws NullPointerException
* if the object is {@code null} and the field is non-static
* @throws IllegalArgumentException
* if the object is not compatible with the declaring class
* @throws IllegalAccessException
* if this field is not accessible
*/
public void setShort(Object object, short value) throws IllegalAccessException,
IllegalArgumentException {
setSField(object, declaringClass, type, slot, flag, TYPE_SHORT, value);
} /**
* Returns a string containing a concise, human-readable description of this
* field.
* <p>
* The format of the string is:
* <ol>
* <li>modifiers (if any)
* <li>type
* <li>declaring class name
* <li>'.'
* <li>field name
* </ol>
* <p>
* For example: {@code public static java.io.InputStream
* java.lang.System.in}
*
* @return a printable representation for this field
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
if (result.length() != 0) {
result.append(' ');
}
appendArrayType(result, type);
result.append(' ');
result.append(declaringClass.getName());
result.append('.');
result.append(name);
return result.toString();
} private native Object getField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck) throws IllegalAccessException; private native double getDField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native int getIField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native long getJField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native boolean getZField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native float getFField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native char getCField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native short getSField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native byte getBField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor) throws IllegalAccessException; private native void setField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, Object value) throws IllegalAccessException; private native void setDField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, double v) throws IllegalAccessException; private native void setIField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, int i) throws IllegalAccessException; private native void setJField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, long j) throws IllegalAccessException; private native void setZField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, boolean z) throws IllegalAccessException; private native void setFField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, float f) throws IllegalAccessException; private native void setCField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, char c) throws IllegalAccessException; private native void setSField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, short s) throws IllegalAccessException; private native void setBField(Object o, Class<?> declaringClass, Class<?> type, int slot,
boolean noAccessCheck, char descriptor, byte b) throws IllegalAccessException; }
Member
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang.reflect; /**
* Common interface providing access to reflective information on class members.
*
* @see Field
* @see Constructor
* @see Method
*/
public interface Member { /**
* Designates all public members of a class or interface (including
* inherited members).
*/
public static final int PUBLIC = 0; /**
* Designates all declared members of a class or interface (without
* inherited members).
*/
public static final int DECLARED = 1; /**
* Returns the class that declares this member.
*
* @return the declaring class
*/
@SuppressWarnings("unchecked")
Class<?> getDeclaringClass(); /**
* Returns the modifiers for this member. The {@link Modifier} class should
* be used to decode the result.
*
* @return the modifiers for this member
*
* @see Modifier
*/
int getModifiers(); /**
* Returns the name of this member.
*
* @return the name of this member
*/
String getName(); /**
* Indicates whether or not this member is synthetic (artificially
* introduced by the compiler).
*
* @return {@code true} if this member is synthetic, {@code false} otherwise
*/
boolean isSynthetic();
}
Method
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang.reflect; import java.lang.annotation.Annotation;
import java.util.Comparator;
import libcore.util.EmptyArray;
import org.apache.harmony.kernel.vm.StringUtils;
import org.apache.harmony.luni.lang.reflect.GenericSignatureParser;
import org.apache.harmony.luni.lang.reflect.ListOfTypes;
import org.apache.harmony.luni.lang.reflect.Types; /**
* This class represents a method. Information about the method can be accessed,
* and the method can be invoked dynamically.
*/
public final class Method extends AccessibleObject implements GenericDeclaration, Member { /**
* Orders methods by their name, parameters and return type.
*
* @hide
*/
public static final Comparator<Method> ORDER_BY_SIGNATURE = new Comparator<Method>() {
public int compare(Method a, Method b) {
int comparison = a.name.compareTo(b.name);
if (comparison != 0) {
return comparison;
} Class<?>[] aParameters = a.parameterTypes;
Class<?>[] bParameters = b.parameterTypes;
int length = Math.min(aParameters.length, bParameters.length);
for (int i = 0; i < length; i++) {
comparison = aParameters[i].getName().compareTo(bParameters[i].getName());
if (comparison != 0) {
return comparison;
}
} if (aParameters.length != bParameters.length) {
return aParameters.length - bParameters.length;
} // this is necessary for methods that have covariant return types.
return a.getReturnType().getName().compareTo(b.getReturnType().getName());
}
}; private int slot; private Class<?> declaringClass; private String name; private Class<?>[] parameterTypes; private Class<?>[] exceptionTypes; private Class<?> returnType; private ListOfTypes genericExceptionTypes;
private ListOfTypes genericParameterTypes;
private Type genericReturnType;
private TypeVariable<Method>[] formalTypeParameters;
private volatile boolean genericTypesAreInitialized = false; private synchronized void initGenericTypes() {
if (!genericTypesAreInitialized) {
String signatureAttribute = getSignatureAttribute();
GenericSignatureParser parser = new GenericSignatureParser(
declaringClass.getClassLoader());
parser.parseForMethod(this, signatureAttribute, exceptionTypes);
formalTypeParameters = parser.formalTypeParameters;
genericParameterTypes = parser.parameterTypes;
genericExceptionTypes = parser.exceptionTypes;
genericReturnType = parser.returnType;
genericTypesAreInitialized = true;
}
} /**
* Construct a clone of the given instance.
*
* @param orig non-null; the original instance to clone
*/
/*package*/ Method(Method orig) {
this(orig.declaringClass, orig.parameterTypes, orig.exceptionTypes,
orig.returnType, orig.name, orig.slot); // Copy the accessible flag.
if (orig.flag) {
this.flag = true;
}
} private Method(Class<?> declaring, Class<?>[] paramTypes, Class<?>[] exceptTypes, Class<?> returnType, String name, int slot)
{
this.declaringClass = declaring;
this.name = name;
this.slot = slot;
this.parameterTypes = paramTypes;
this.exceptionTypes = exceptTypes; // may be null
this.returnType = returnType;
} public TypeVariable<Method>[] getTypeParameters() {
initGenericTypes();
return formalTypeParameters.clone();
} /** {@inheritDoc} */
@Override /*package*/ String getSignatureAttribute() {
Object[] annotation = getSignatureAnnotation(declaringClass, slot); if (annotation == null) {
return null;
} return StringUtils.combineStrings(annotation);
} /**
* Returns the Signature annotation for this method. Returns {@code null} if
* not found.
*/
static native Object[] getSignatureAnnotation(Class declaringClass, int slot); /**
* Returns the string representation of the method's declaration, including
* the type parameters.
*
* @return the string representation of this method
*/
public String toGenericString() {
StringBuilder sb = new StringBuilder(80); initGenericTypes(); // append modifiers if any
int modifier = getModifiers();
if (modifier != 0) {
sb.append(Modifier.toString(modifier & ~(Modifier.BRIDGE +
Modifier.VARARGS))).append(' ');
}
// append type parameters
if (formalTypeParameters != null && formalTypeParameters.length > 0) {
sb.append('<');
for (int i = 0; i < formalTypeParameters.length; i++) {
appendGenericType(sb, formalTypeParameters[i]);
if (i < formalTypeParameters.length - 1) {
sb.append(",");
}
}
sb.append("> ");
}
// append return type
appendGenericType(sb, Types.getType(genericReturnType));
sb.append(' ');
// append method name
appendArrayType(sb, getDeclaringClass());
sb.append(".").append(getName());
// append parameters
sb.append('(');
appendArrayGenericType(sb,
Types.getClonedTypeArray(genericParameterTypes));
sb.append(')');
// append exceptions if any
Type[] genericExceptionTypeArray = Types.getClonedTypeArray(
genericExceptionTypes);
if (genericExceptionTypeArray.length > 0) {
sb.append(" throws ");
appendArrayGenericType(sb, genericExceptionTypeArray);
}
return sb.toString();
} /**
* Returns the parameter types as an array of {@code Type} instances, in
* declaration order. If this method has no parameters, an empty array is
* returned.
*
* @return the parameter types
*
* @throws GenericSignatureFormatError
* if the generic method signature is invalid
* @throws TypeNotPresentException
* if any parameter type points to a missing type
* @throws MalformedParameterizedTypeException
* if any parameter type points to a type that cannot be
* instantiated for some reason
*/
public Type[] getGenericParameterTypes() {
initGenericTypes();
return Types.getClonedTypeArray(genericParameterTypes);
} /**
* Returns the exception types as an array of {@code Type} instances. If
* this method has no declared exceptions, an empty array will be returned.
*
* @return an array of generic exception types
*
* @throws GenericSignatureFormatError
* if the generic method signature is invalid
* @throws TypeNotPresentException
* if any exception type points to a missing type
* @throws MalformedParameterizedTypeException
* if any exception type points to a type that cannot be
* instantiated for some reason
*/
public Type[] getGenericExceptionTypes() {
initGenericTypes();
return Types.getClonedTypeArray(genericExceptionTypes);
} /**
* Returns the return type of this method as a {@code Type} instance.
*
* @return the return type of this method
*
* @throws GenericSignatureFormatError
* if the generic method signature is invalid
* @throws TypeNotPresentException
* if the return type points to a missing type
* @throws MalformedParameterizedTypeException
* if the return type points to a type that cannot be
* instantiated for some reason
*/
public Type getGenericReturnType() {
initGenericTypes();
return Types.getType(genericReturnType);
} @Override
public Annotation[] getDeclaredAnnotations() {
return getDeclaredAnnotations(declaringClass, slot);
}
static native Annotation[] getDeclaredAnnotations(Class<?> declaringClass, int slot); @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
return getAnnotation(declaringClass, slot, annotationType);
}
static native <A extends Annotation> A getAnnotation(
Class<?> declaringClass, int slot, Class<A> annotationType); @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
return isAnnotationPresent(declaringClass, slot, annotationType);
}
static native boolean isAnnotationPresent(
Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType); private static final Annotation[] NO_ANNOTATIONS = new Annotation[0]; /**
* Creates an array of empty Annotation arrays.
*/
/*package*/ static Annotation[][] noAnnotations(int size) {
Annotation[][] annotations = new Annotation[size][];
for (int i = 0; i < size; i++) {
annotations[i] = NO_ANNOTATIONS;
}
return annotations;
} /**
* Returns an array of arrays that represent the annotations of the formal
* parameters of this method. If there are no parameters on this method,
* then an empty array is returned. If there are no annotations set, then
* and array of empty arrays is returned.
*
* @return an array of arrays of {@code Annotation} instances
*/
public Annotation[][] getParameterAnnotations() {
Annotation[][] parameterAnnotations
= getParameterAnnotations(declaringClass, slot);
if (parameterAnnotations.length == 0) {
return noAnnotations(parameterTypes.length);
}
return parameterAnnotations;
} static native Annotation[][] getParameterAnnotations(Class declaringClass, int slot); /**
* Indicates whether or not this method takes a variable number argument.
*
* @return {@code true} if a vararg is declared, {@code false} otherwise
*/
public boolean isVarArgs() {
int modifiers = getMethodModifiers(declaringClass, slot);
return (modifiers & Modifier.VARARGS) != 0;
} /**
* Indicates whether or not this method is a bridge.
*
* @return {@code true} if this method is a bridge, {@code false} otherwise
*/
public boolean isBridge() {
int modifiers = getMethodModifiers(declaringClass, slot);
return (modifiers & Modifier.BRIDGE) != 0;
} /**
* Indicates whether or not this method is synthetic.
*
* @return {@code true} if this method is synthetic, {@code false} otherwise
*/
public boolean isSynthetic() {
int modifiers = getMethodModifiers(declaringClass, slot);
return (modifiers & Modifier.SYNTHETIC) != 0;
} /**
* Returns the default value for the annotation member represented by this
* method.
*
* @return the default value, or {@code null} if none
*
* @throws TypeNotPresentException
* if this annotation member is of type {@code Class} and no
* definition can be found
*/
public Object getDefaultValue() {
return getDefaultValue(declaringClass, slot);
}
native private Object getDefaultValue(Class declaringClass, int slot); /**
* Indicates whether or not the specified {@code object} is equal to this
* method. To be equal, the specified object must be an instance
* of {@code Method} with the same declaring class and parameter types
* as this method.
*
* @param object
* the object to compare
*
* @return {@code true} if the specified object is equal to this
* method, {@code false} otherwise
*
* @see #hashCode
*/
@Override
public boolean equals(Object object) {
return object instanceof Method && toString().equals(object.toString());
} /**
* Returns the class that declares this method.
*
* @return the declaring class
*/
public Class<?> getDeclaringClass() {
return declaringClass;
} /**
* Returns the exception types as an array of {@code Class} instances. If
* this method has no declared exceptions, an empty array is returned.
*
* @return the declared exception classes
*/
public Class<?>[] getExceptionTypes() {
if (exceptionTypes == null) {
return EmptyArray.CLASS;
}
return exceptionTypes.clone();
} /**
* Returns the modifiers for this method. The {@link Modifier} class should
* be used to decode the result.
*
* @return the modifiers for this method
*
* @see Modifier
*/
public int getModifiers() {
return getMethodModifiers(declaringClass, slot);
} static native int getMethodModifiers(Class<?> declaringClass, int slot); /**
* Returns the name of the method represented by this {@code Method}
* instance.
*
* @return the name of this method
*/
public String getName() {
return name;
} /**
* Returns an array of {@code Class} objects associated with the parameter
* types of this method. If the method was declared with no parameters, an
* empty array will be returned.
*
* @return the parameter types
*/
public Class<?>[] getParameterTypes() {
return parameterTypes.clone();
} /**
* Returns the {@code Class} associated with the return type of this
* method.
*
* @return the return type
*/
public Class<?> getReturnType() {
return returnType;
} /**
* Returns an integer hash code for this method. Objects which are equal
* return the same value for this method. The hash code for this Method is
* the hash code of the name of this method.
*
* @return hash code for this method
*
* @see #equals
*/
@Override
public int hashCode() {
return name.hashCode();
} /**
* Returns the result of dynamically invoking this method. Equivalent to
* {@code receiver.methodName(arg1, arg2, ... , argN)}.
*
* <p>If the method is static, the receiver argument is ignored (and may be null).
*
* <p>If the method takes no arguments, you can pass {@code (Object[]) null} instead of
* allocating an empty array.
*
* <p>If you're calling a varargs method, you need to pass an {@code Object[]} for the
* varargs parameter: that conversion is usually done in {@code javac}, not the VM, and
* the reflection machinery does not do this for you. (It couldn't, because it would be
* ambiguous.)
*
* <p>Reflective method invocation follows the usual process for method lookup.
*
* <p>If an exception is thrown during the invocation it is caught and
* wrapped in an InvocationTargetException. This exception is then thrown.
*
* <p>If the invocation completes normally, the return value itself is
* returned. If the method is declared to return a primitive type, the
* return value is boxed. If the return type is void, null is returned.
*
* @param receiver
* the object on which to call this method (or null for static methods)
* @param args
* the arguments to the method
* @return the result
*
* @throws NullPointerException
* if {@code receiver == null} for a non-static method
* @throws IllegalAccessException
* if this method is not accessible (see {@link AccessibleObject})
* @throws IllegalArgumentException
* if the number of arguments doesn't match the number of parameters, the receiver
* is incompatible with the declaring class, or an argument could not be unboxed
* or converted by a widening conversion to the corresponding parameter type
* @throws InvocationTargetException
* if an exception was thrown by the invoked method
*/
public Object invoke(Object receiver, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (args == null) {
args = EmptyArray.OBJECT;
}
return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);
} private native Object invokeNative(Object obj, Object[] args, Class<?> declaringClass,
Class<?>[] parameterTypes, Class<?> returnType, int slot, boolean noAccessCheck)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException; /**
* Returns a string containing a concise, human-readable description of this
* method. The format of the string is:
*
* <ol>
* <li>modifiers (if any)
* <li>return type or 'void'
* <li>declaring class name
* <li>'('
* <li>parameter types, separated by ',' (if any)
* <li>')'
* <li>'throws' plus exception types, separated by ',' (if any)
* </ol>
*
* For example: {@code public native Object
* java.lang.Method.invoke(Object,Object) throws
* IllegalAccessException,IllegalArgumentException
* ,InvocationTargetException}
*
* @return a printable representation for this method
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder(Modifier.toString(getModifiers())); if (result.length() != 0)
result.append(' ');
result.append(returnType.getName());
result.append(' ');
result.append(declaringClass.getName());
result.append('.');
result.append(name);
result.append("(");
result.append(toString(parameterTypes));
result.append(")");
if (exceptionTypes != null && exceptionTypes.length != 0) {
result.append(" throws ");
result.append(toString(exceptionTypes));
} return result.toString();
} /**
* Returns the constructor's signature in non-printable form. This is called
* (only) from IO native code and needed for deriving the serialVersionUID
* of the class
*
* @return The constructor's signature.
*/
@SuppressWarnings("unused")
private String getSignature() {
StringBuilder result = new StringBuilder(); result.append('(');
for (int i = 0; i < parameterTypes.length; i++) {
result.append(getSignature(parameterTypes[i]));
}
result.append(')');
result.append(getSignature(returnType)); return result.toString();
} }
Modifier
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package java.lang.reflect; /**
* This class provides static methods to decode class and member modifiers.
*
* @see Class#getModifiers()
* @see Member#getModifiers()
*/
public class Modifier { /**
* The {@code int} value representing the {@code public}
* modifier.
*/
public static final int PUBLIC = 0x1; /**
* The {@code int} value representing the {@code private}
* modifier.
*/
public static final int PRIVATE = 0x2; /**
* The {@code int} value representing the {@code protected}
* modifier.
*/
public static final int PROTECTED = 0x4; /**
* The {@code int} value representing the {@code static} modifier.
*/
public static final int STATIC = 0x8; /**
* The {@code int} value representing the {@code final} modifier.
*/
public static final int FINAL = 0x10; /**
* The {@code int} value representing the {@code synchronized}
* modifier.
*/
public static final int SYNCHRONIZED = 0x20; /**
* The {@code int} value representing the {@code volatile}
* modifier.
*/
public static final int VOLATILE = 0x40; /**
* The {@code int} value representing the {@code transient}
* modifier.
*/
public static final int TRANSIENT = 0x80; /**
* The {@code int} value representing the {@code native} modifier.
*/
public static final int NATIVE = 0x100; /**
* The {@code int} value representing the {@code interface}
* modifier.
*/
public static final int INTERFACE = 0x200; /**
* The {@code int} value representing the {@code abstract}
* modifier.
*/
public static final int ABSTRACT = 0x400; /**
* The {@code int} value representing the {@code strict} modifier.
*/
public static final int STRICT = 0x800; // Non-public types required by Java 5 update to class file format
static final int BRIDGE = 0x40; static final int VARARGS = 0x80; static final int SYNTHETIC = 0x1000; static final int ANNOTATION = 0x2000; static final int ENUM = 0x4000; /**
* Constructs a new {@code Modifier} instance.
*/
public Modifier() {
} /**
* Returns a mask of all the modifiers that may be applied to classes.
* @since 1.7
* @hide 1.7
*/
public static int classModifiers() {
return PUBLIC | PROTECTED | PRIVATE | ABSTRACT | STATIC | FINAL | STRICT;
} /**
* Returns a mask of all the modifiers that may be applied to constructors.
* @since 1.7
* @hide 1.7
*/
public static int constructorModifiers() {
return PUBLIC | PROTECTED | PRIVATE;
} /**
* Returns a mask of all the modifiers that may be applied to fields.
* @since 1.7
* @hide 1.7
*/
public static int fieldModifiers() {
return PUBLIC | PROTECTED | PRIVATE | STATIC | FINAL | TRANSIENT | VOLATILE;
} /**
* Returns a mask of all the modifiers that may be applied to interfaces.
* @since 1.7
* @hide 1.7
*/
public static int interfaceModifiers() {
return PUBLIC | PROTECTED | PRIVATE | ABSTRACT | STATIC | STRICT;
} /**
* Returns a mask of all the modifiers that may be applied to methods.
* @since 1.7
* @hide 1.7
*/
public static int methodModifiers() {
return PUBLIC | PROTECTED | PRIVATE | ABSTRACT | STATIC | FINAL | SYNCHRONIZED | NATIVE | STRICT;
} /**
* Indicates whether or not the specified modifiers contain the {@code
* abstract} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* abstract} modifier, {@code false} otherwise
*/
public static boolean isAbstract(int modifiers) {
return ((modifiers & ABSTRACT) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* final} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* final} modifier, {@code false} otherwise
*/
public static boolean isFinal(int modifiers) {
return ((modifiers & FINAL) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* interface} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* interface} modifier, {@code false} otherwise
*/
public static boolean isInterface(int modifiers) {
return ((modifiers & INTERFACE) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* native} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* native} modifier, {@code false} otherwise
*/
public static boolean isNative(int modifiers) {
return ((modifiers & NATIVE) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* private} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* private} modifier, {@code false} otherwise
*/
public static boolean isPrivate(int modifiers) {
return ((modifiers & PRIVATE) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* protected} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* protected} modifier, {@code false} otherwise
*/
public static boolean isProtected(int modifiers) {
return ((modifiers & PROTECTED) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* public} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* public} modifier, {@code false} otherwise
*/
public static boolean isPublic(int modifiers) {
return ((modifiers & PUBLIC) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* static} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* static} modifier, {@code false} otherwise
*/
public static boolean isStatic(int modifiers) {
return ((modifiers & STATIC) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* strict} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* strict} modifier, {@code false} otherwise
*/
public static boolean isStrict(int modifiers) {
return ((modifiers & STRICT) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* synchronized} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* synchronized} modifier, {@code false} otherwise
*/
public static boolean isSynchronized(int modifiers) {
return ((modifiers & SYNCHRONIZED) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* transient} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* transient} modifier, {@code false} otherwise
*/
public static boolean isTransient(int modifiers) {
return ((modifiers & TRANSIENT) != 0);
} /**
* Indicates whether or not the specified modifiers contain the {@code
* volatile} modifier.
*
* @param modifiers
* the modifiers to test
* @return {@code true} if the specified modifiers contain the {@code
* volatile} modifier, {@code false} otherwise
*/
public static boolean isVolatile(int modifiers) {
return ((modifiers & VOLATILE) != 0);
} /**
* Returns a string containing the string representation of all modifiers
* present in the specified modifiers. Modifiers appear in the order
* specified by the Java Language Specification:
*
* {@code public private protected abstract static final transient volatile native synchronized interface strict}
*
* @param modifiers
* the modifiers to print
* @return a printable representation of the modifiers
*/
public static java.lang.String toString(int modifiers) {
StringBuilder buf = new StringBuilder(); if (isPublic(modifiers)) {
buf.append("public ");
}
if (isProtected(modifiers)) {
buf.append("protected ");
}
if (isPrivate(modifiers)) {
buf.append("private ");
}
if (isAbstract(modifiers)) {
buf.append("abstract ");
}
if (isStatic(modifiers)) {
buf.append("static ");
}
if (isFinal(modifiers)) {
buf.append("final ");
}
if (isTransient(modifiers)) {
buf.append("transient ");
}
if (isVolatile(modifiers)) {
buf.append("volatile ");
}
if (isSynchronized(modifiers)) {
buf.append("synchronized ");
}
if (isNative(modifiers)) {
buf.append("native ");
}
if (isStrict(modifiers)) {
buf.append("strictfp ");
}
if (isInterface(modifiers)) {
buf.append("interface ");
}
if (buf.length() == 0) {
return "";
}
buf.setLength(buf.length() - 1);
return buf.toString();
}
}
- 运行期类型鉴定(RTTI)的概念初看非常简单——手上只有基础类型的一个句柄时,利用它判断一个对象的正确类型。一种是“传统”RTTI,它假定我们已在编译和运行期拥有所有类型;另一种是Java1.1特有的“反射”机制,利用它可在运行期独立查找类信息。
- In C++, dynamic_cast and typeid operator works only for class with virtual function. In fact, type_info is inserted in the first slot of vtble, if vtble exist.
- 为理解RTTI在Java里如何工作,首先必须了解类型信息在运行期是如何表示的。这时要用到一个名为“Class对象”的特殊形式的对象,其中包含了与类有关的信息(有时也把它叫作“元类”)。事实上,我们要用Class对象创建属于某个类的全部“常规”或“普通”对象。对于作为程序一部分的每个类,它们都有一个Class对象。换言之,每次写一个新类时,同时也会创建一个Class对象(更恰当地说,是保存在一个完全同名的.class文件中)。在运行期,一旦我们想生成那个类的一个对象,用于执行程序的Java虚拟机(JVM)首先就会检查那个类型的Class对象是否已经载入。若尚未载入,JVM就会查找同名的.class文件,并将其载入。所以Java程序启动时并不是完全载入的,这一点与许多传统语言都不同。一旦那个类型的Class对象进入内存,就用它创建那一类型的所有对象。
- Class.forName("Gum");
该方法是Class(即全部Class所从属的)的一个static成员。而Class对象和其他任何对象都是类似的,所以能够获取和控制它的一个句柄(装载模块就是干这件事的)。为获得Class的一个句柄,一个办法是使用forName()。它的作用是取得包含了目标类文本名字的一个String(注意拼写和大小写)。最后返回的是一个Class句柄。 - Class.forName("Gum");
该方法是Class(即全部Class所从属的)的一个static成员。而Class对象和其他任何对象都是类似的,所以能够获取和控制它的一个句柄(装载模块就是干这件事的)。为获得Class的一个句柄,一个办法是使用forName()。它的作用是取得包含了目标类文本名字的一个String(注意拼写和大小写)。最后返回的是一个Class句柄。 - RTTI在Java中存在三种形式。关键字instanceof告诉我们对象是不是一个特定类型的实例(Instance即“实例”)。它会返回一个布尔值,以便以问题的形式使用,就象下面这样:if(x instanceof Dog)
- 首先必须获得指向适当Class对象的的一个句柄。就象前例演示的那样,一个办法是用一个字串以及Class.forName()方法。这是非常方便的,因为不需要那种类型的一个对象来获取Class句柄。然而,对于自己感兴趣的类型,如果已有了它的一个对象,那么为了取得Class句柄,可调用属于Object根类一部分的一个方法:getClass()。它的作用是返回一个特定的Class句柄,用来表示对象的实际类型。
- 若从表面看,Class的newInstance()方法似乎是克隆(clone())一个对象的另一种手段。但两者是有区别的。利用newInstance(),我们可在没有现成对象供“克隆”的情况下新建一个对象。就象上面的程序演示的那样,当时没有Toy对象,只有cy——即y的Class对象的一个句柄。利用它可以实现“虚拟构建器”。换言之,我们表达:“尽管我不知道你的准确类型是什么,但请你无论如何都正确地创建自己。
- 如果不知道一个对象的准确类型,RTTI会帮助我们调查。但却有一个限制:类型必须是在编译期间已知的,否则就不能用RTTI调查它,进而无法展开下一步的工作。换言之,编译器必须明确知道RTTI要处理的所有类。
- 用“快速应用开发”(RAD)模型来构建程序项目。RAD一般是在应用程序构建工具中内建的。这是编制程序的一种可视途径(在屏幕上以窗体的形式出现)。可将代表不同组件的图标拖曳到窗体中。随后,通过设定这些组件的属性或者值,进行正确的配置。设计期间的配置要求任何组件都是可以“例示”的(即可以自由获得它们的实例)。这些组件也要揭示出自己的一部分内容,允许程序员读取和设置各种值。此外,用于控制GUI事件的组件必须揭示出与相应的方法有关的信息,以便RAD环境帮助程序员用自己的代码覆盖这些由事件驱动的方法。“反射”提供了一种特殊的机制,可以侦测可用的方法,并产生方法名。通过Java Beans(第13章将详细介绍),Java 1.1为这种基于组件的程序设计提供了一个基础结构。
- 在运行期查询类信息的另一个原动力是通过网络创建与执行位于远程系统上的对象。这就叫作“远程方法调用”(RMI),它允许Java程序(版本1.1以上)使用由多台机器发布或分布的对象。这种对象的分布可能是由多方面的原因引起的:可能要做一件计算密集型的工作,想对它进行分割,让处于空闲状态的其他机器分担部分工作,从而加快处理进度。某些情况下,可能需要将用于控制特定类型任务(比如多层客户/服务器架构中的“运作规则”)的代码放置在一台特殊的机器上,使这台机器成为对那些行动进行描述的一个通用储藏所。而且可以方便地修改这个场所,使其对系统内的所有方面产生影响(这是一种特别有用的设计思路,因为机器是独立存在的,所以能轻易修改软件!)。分布式计算也能更充分地发挥某些专用硬件的作用,它们特别擅长执行一些特定的任务——例如矩阵逆转——但对常规编程来说却显得太夸张或者太昂贵了。
- Class类(本章前面已有详细论述)得到了扩展,可以支持“反射”的概念。针对Field,Method以及Constructor类(每个都实现了Memberinterface——成员接口),它们都新增了一个库:java.lang.reflect。这些类型的对象都是JVM在运行期创建的,用于代表未知类里对应的成员。这样便可用构建器创建新对象,用get()和set()方法读取和修改与Field对象关联的字段,以及用invoke()方法调用与Method对象关联的方法。此外,我们可调用方法getFields(),getMethods(),getConstructors(),分别返回用于表示字段、方法以及构建器的对象数组(在联机文档中,还可找到与Class类有关的更多的资料)。因此,匿名对象的类信息可在运行期被完整的揭露出来,而在编译期间不需要知道任何东西。
- 通过“反射”同一个未知类型的对象打交道时,JVM只是简单地检查那个对象,并调查它从属于哪个特定的类(就象以前的RTTI那样)。但在这之后,在我们做其他任何事情之前,Class对象必须载入。因此,用于那种特定类型的.class文件必须能由JVM调用(要么在本地机器内,要么可以通过网络取得)。所以RTTI和“反射”之间唯一的区别就是对RTTI来说,编译器会在编译期打开和检查.class文件。换句话说,我们可以用“普通”方式调用一个对象的所有方法;但对“反射”来说,.class文件在编译期间是不可使用的,而是由运行期环境打开和检查。
- Class方法getMethods()和getConstructors()可以分别返回Method和Constructor的一个数组。每个类都提供了进一步的方法,可解析出它们所代表的方法的名字、参数以及返回值。但也可以象这样一样只使用toString(),生成一个含有完整方法签名的字串。
Java Exception & RTTI的更多相关文章
- myeclipse启动tomcat会出现 a java exception has occured错误 的解决方法
在浏览器中可以打开tomcat,结果在myeclipse启动tomcat会出现 a java exception has occured错误 ,之后出现一个Classloader.class的文件,关 ...
- eclipse启动tomcat错误:A Java Exception has occurred
在tomcat bin目录下执行startup.bat可以正常启动,但在eclipse下安装了tomcat插件并且配置tomcat路径后启动且报错:A Java Exception has occur ...
- eclipse启动tomcat错误:A Java Exception has occurred(转)
在tomcat bin目录下执行startup.bat可以正常启动,但在eclipse下安装了tomcat插件并且配置tomcat路径后启动且报错:A Java Exception has occur ...
- CTFCrackTools在Windows下显示A Java Exception has occurred的解决方案
打CTF做密码学的人一定少不了用这个工具,CTFCrackTools,这个几乎可以号称密码学的神器,但是呢,最近博主遇到了一些麻烦事,每次打开的时候都是显示A Java Exception has o ...
- java的RTTI和反射机制
RTTI,即Run-Time Type Identification,运行时类型识别.RTTI能在运行时就能够自动识别每个编译时已知的类型. 很多时候需要进行向上转型,比如Base类派生出Derive ...
- Exception (2) Java Exception Handling
The Java programming language uses exceptions to handle errors and other exceptional events.An excep ...
- Kettle 7启动 Spoon.bat 时报错“A Java Exception has occurred.”的解决方法
最近在研究Kettle 时出现启动时报错“A Java Exception has occurred.”的问题.刚开始没搞明白是什么原因,后来发现是jdk版本的问题.出现这个错误原因是 Kettle ...
- MyEclipse 运行弹出A Java Exception has occurred.
问题描述 A Java Exception has occurred. 问题原因 这个问题是由较高版本的JDK编译的java class文件试图在较低版本的JVM上运行而产生的错误
- Kettle启动时报错Cannot create java virtual machine & A java exception has occurred
开源免费--最喜欢的四个字没有之一 1.官网下载 https://sourceforge.net/projects/pentaho/files/Data%20Integration/ 下载完后,解压即 ...
随机推荐
- 2019.2.25考试T1, 矩阵快速幂加速递推+单位根反演(容斥)
\(\color{#0066ff}{题解}\) 然后a,b,c通过矩阵加速即可 为什么1出现偶数次3没出现的贡献是上面画绿线的部分呢? 考虑暴力统计这部分贡献,答案为\(\begin{aligned} ...
- 10.19 qbxt国庆day3
最近的题都莫名简单 经常AK 炼金术 [问题描述] 即使是最伟大的ACM选手也是需要足够的金钱来把妹的的.于是ZYB发明了一台炼金机器. 这台机器一共有三个功能: 1.能把a位沙子变成b位石油. 2. ...
- Centos7安装MySQL8.0
请到这个地址看:https://www.cnblogs.com/kevingrace/p/10482469.html Centos7安装MySQL8.0 - 操作手册 一.yum安装方式: 卸载之前版 ...
- python3 unittest数据驱动
我们在自动化测试的时候,有没有遇到这样的问题?例如一个登录的接口要做自动化,会有很多case(用例),密码错误,密码正确这种.在继承unittest.TestCase的类中,凡是以“test”开头的方 ...
- 使用Spring和JQuery实现视频文件的上传和播放
Spring MVC可以很方便用户进行WEB应用的开发,实现Model.View和Controller的分离,再结合Spring boot可以很方便.轻量级部署WEB应用,这里为大家介绍如何使用Spr ...
- sf04_操作系统中 heap 和 stack 的区别
概述 本文分三部分,描述有所重叠,但可以让你对栈与堆有一个比较清晰.全面的认识 heap 和 stack是什么 堆栈是两种数据结构.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top) ...
- Oracle 12c DG备库Alert报错ORA-01110
环境是12.2.0.1 version, Oracle Data Guard备库近段时间一直报错,但是备库主库同步一致,数据一致. 2019-03-06T23:42:22.184048+08:00 E ...
- shiro【filter】
alt+7 OncePerRequestFilter public final void doFilter(ServletRequest request, ServletResponse respon ...
- kafka与zookeeper读写分析
kafka的读写都通过leader完成,而zookeeper只有写要通过leader而读可以通过任意follower,我觉得造成这种差异的原因还是在于使用场景. kafka的设计目标是实现一个高吞吐的 ...
- Idea创建Maven项目没有src
第一次创建,下载非常慢,解决方法 1.配置环境变量 第二种:创建Maven项目时加上 archetypeCatalog=internal 参数 第三种:为自己的Maven配置国内镜像源 打开自己的 M ...