我对类加载的理解是一个类在第一次需要时被加载(以非常简单的方式放置).使用-verbose:class和Iterators类的修改版本运行以下示例,该类在调用其clinit时打印消息我观察到了一些我无法解释的内容:
public class IteratorsTest
{
public static void main(String[] args)
{
com.google.common.collect.Iterators.forArray(1, 2, 3);
}
}
Run Code Online (Sandbox Code Playgroud)
(清理)输出如下:
[Loaded com.google.common.collect.Iterators from file:...]
[Loaded com.google.common.collect.Iterators$1 from file:...]
---------> Iterators <clinit>
Run Code Online (Sandbox Code Playgroud)
为什么在调用clinit之前加载Iterators $ 1?它只在临床中定义,不是吗?
static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR =
new UnmodifiableListIterator<Object>() {
...
}
Run Code Online (Sandbox Code Playgroud)
这导致以下字节代码:
static <clinit>()V
L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "---------> Iterators clinit --------------"**
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
NEW com/google/common/collect/Iterators$1
DUP
INVOKESPECIAL com/google/common/collect/Iterators$1.<init> ()V
L2
PUTSTATIC com/google/common/collect/Iterators.EMPTY_LIST_ITERATOR : Lcom/google/common/collect/UnmodifiableListIterator;
Run Code Online (Sandbox Code Playgroud)
为了让我更加困惑,我还有一个样本(太复杂了,无法在此处发布),其中与上面主要内容相同的代码行导致以下输出:
[Loaded com.google.common.collect.Iterators from file:...]
---------> Iterators <clinit>
[Loaded com.google.common.collect.Iterators$1 from …Run Code Online (Sandbox Code Playgroud) 有人可以解释一下以下是什么吗?
public class Stuff
{
static
{
try
{
Class.forName("com.mysql.jdbc.Driver");
}
catch ( ClassNotFoundException exception )
{
log.error( "ClassNotFoundException " + exception.getMessage( ) );
}
...
}
Run Code Online (Sandbox Code Playgroud)
这静态{...}做了什么?
我知道来自C++的静态变量,但这是一个静态块还是什么?
什么时候这个东西会被执行?
public class Main {
public static final Logger LOGGER = Logger.getLogger(Main.class.getName());
static {
try {
LOGGER.addHandler(new FileHandler("errors.log",true));
}
catch(IOException ex) {
LOGGER.log(Level.WARNING,ex.toString(),ex);
}
}
...
Run Code Online (Sandbox Code Playgroud)
我想知道这个无名静态功能是什么.
我在java(我目前正在学习)中从未见过这样的东西.
它是为了什么?
什么时候通常使用?
什么时候会在程序中执行?
我预计以下代码会产生分段错误(或其他UB):
struct T {
T();
};
T t;
char const* str = "Test string";
T::T() {
std::cout << str; // zero-initialised, only!
}
int main() {}
Run Code Online (Sandbox Code Playgroud)
那是因为t之前已经初始化了str.我期望由于零初始化而str保持该值(char const*)0.我的解释[C++11: 3.6.2/2]支持这一点.
但是,上面的代码片段似乎按预期输出了字符串(我也通过打印指针的值来确认行为).
我是否缺少一些静态初始化规则,允许str在t开始构建之前进行值初始化?标准在哪里?
这在构建时出现了静态变量解析,其中一个回答者断言使用char const*而不是std::string静态全局避免了静态初始化顺序惨败.我不同意,但现在我不太确定......
我注意到静态初始化器中的某些内容可能是javac中的一个错误.我构建了一个场景,我可以为变量赋值,但不能读回该值.
下面是两个示例,第一个编译正常,第二个在尝试从tmp读取值时出错,但由于某种原因,允许为tmp分配值.我可以理解它是否既不能读取也不能写入变量,因为tmp是在静态初始化器之后声明的,但是只有其中一个错误对我来说没有意义.
//Compiles Successfully:
public class Script
{
public static Object tmp;
static
{
tmp = new Object();
System.out.println(tmp);
}
}
//error only on the read but not the assignment
public class Script
{
static
{
tmp = new Object();
System.out.println(tmp);
}
public static Object tmp;
}
Run Code Online (Sandbox Code Playgroud)
为了进一步强调这一点,这确实可以成功编译.
public class Script
{
static
{
tmp = new Object();
}
public static Object tmp;
}
Run Code Online (Sandbox Code Playgroud) 我可以从Java中的静态初始化程序调用静态方法吗?以下是否有效并保证按照Java规范工作?
public class Foo {
private final static int bar;
private static int generateValue() {
return 123;
}
static {
bar = generateValue();
}
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,我可能期望bar在里面可用generateValue().我知道静态初始化程序块的顺序很重要,但我没有听说静态方法声明的顺序很重要.但是,在执行静态初始化程序块之前,静态方法是否可用?
一旦加载了类,有没有办法再次调用静态初始值设定项?
public class Foo {
static {
System.out.println("bar");
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我需要调用静态初始化程序,因为我没有编写原始类,我需要调用的逻辑是在静态初始化程序中实现的.
我有一个Set类(这是J2ME,所以我对标准API的访问权限有限;只是为了解释我明显的轮子改造).我正在使用我的set类在类和子类中创建常量集.它看起来像这样......
class ParentClass
{
protected final static Set THE_SET = new Set() {{
add("one");
add("two");
add("three");
}};
}
class SubClass extends ParentClass
{
protected final static Set THE_SET = new Set() {{
add("four");
add("five");
add("six");
union(ParentClass.THE_SET); /* [1] */
}};
}
Run Code Online (Sandbox Code Playgroud)
除了[1]处的行导致空指针异常外,所有看起来都很好.据推测,这意味着子类中的静态初始化程序在父类的运行之前运行.这让我感到惊讶,因为我认为它会先在任何新的导入中运行静态块,然后再在instatiated子类中运行.
我在这个假设中是对的吗?有没有办法控制或解决这种行为?
更新:
事情甚至更奇怪.我尝试了这个(注意'new ParentClass()'行):
class ParentClass
{
public ParentClass()
{
System.out.println(THE_SET);
}
protected final static Set THE_SET = new Set() {{
add("one");
add("two");
add("three");
}};
}
class SubClass extends ParentClass
{
protected final static Set THE_SET = new …Run Code Online (Sandbox Code Playgroud) 是否可以从静态初始化块内部获取类类型?
这是我目前拥有的简化版本::
class Person extends SuperClass {
String firstName;
static{
// This function is on the "SuperClass":
// I'd for this function to be able to get "Person.class" without me
// having to explicitly type it in but "this.class" does not work in
// a static context.
doSomeReflectionStuff(Person.class); // IN "SuperClass"
}
}
Run Code Online (Sandbox Code Playgroud)
这更接近我正在做的事情,即初始化一个保存有关对象及其注释等信息的数据结构......也许我使用了错误的模式?
public abstract SuperClass{
static void doSomeReflectionStuff( Class<?> classType, List<FieldData> fieldDataList ){
Field[] fields = classType.getDeclaredFields();
for( Field field : fields ){
// Initialize fieldDataList
}
} …Run Code Online (Sandbox Code Playgroud) 我最近发现在我看来是静态初始化ArrayList的新语法:
new ArrayList() {{
add("first");
add("second");
}};
我的问题是,那里到底发生了什么?这是定义静态块的快捷方式(我认为它需要static关键字)?或者只是一种定义默认构造函数的方法?别的什么?哪个版本的Java有效?
将非常感谢解释以及进一步阅读的链接.
编辑:我的测试类,用于显示初始化程序块是否在构造函数之前或之后执行.结果显示初始化程序块在其他构造函数代码之前执行:
import org.junit.Test;
public class InitializerBlockTest {
class InitializerTest {
{
System.out.println("Running initalizer block");
}
public InitializerTest() {
System.out.println("Running default constructor");
}
}
class SubClass extends InitializerTest {
{
System.out.println("Running subclass Initializer block");
}
public SubClass() {
System.out.println("Running subclass constructor");
}
}
@Test
public void testIt() {
new SubClass();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Running initalizer block
Running default constructor
Running subclass Initializer block
Running subclass constructor
Run Code Online (Sandbox Code Playgroud) java ×9
static ×3
arraylist ×1
bytecode ×1
c++ ×1
classloader ×1
function ×1
inheritance ×1
jvm ×1
reflection ×1