为什么不能使用声明类作为限定符(以静态方式)从相应的静态初始化程序访问静态最终字段?
起初,我认为这是一个Eclipse bug:

我还缺乏一些知识,因为静态初始化器不是我的日常业务.但是,看哪,这没有预期的类限定符:

为了完成我的测试系列,我在bash中尝试了一下:

导致相同的结果.
这引出了我最后的问题:
从静态初始化程序块访问静态最终字段时是否有任何理由禁止类限定符?因为声明类之前没有初始化?
Quoth JLS#8.1.3:
内部类可能不会声明静态初始化器(第8.7节)......
这表现如下:
class A {
class B {
static { // Compile-time Error: Cannot define static initializer in inner type A.B
System.out.println("Class is initializing...");
}
}
}
Run Code Online (Sandbox Code Playgroud)
既然Java的内部(非静态)类是由类加载器加载的,就像其他类一样,为什么我们不能为它们安装静态初始化器?
这种限制背后的原因是什么?
我有一个用大量香草char*指针定义的结构,但也是一个对象成员.当我尝试静态初始化这样的结构时,我得到编译器错误.
typedef struct
{
const char* pszA;
// ... snip ...
const char* pszZ;
SomeObject obj;
} example_struct;
// I only want to assign the first few members, the rest should be default
example_struct ex = { "a", "b" };
Run Code Online (Sandbox Code Playgroud)
SomeObject有一个没有参数的公共默认构造函数,所以我不认为这会是一个问题.但是当我尝试编译它(使用VS)时,我收到以下错误:
error C2248: 'SomeObject::SomeObject' : cannot access private member declared in class 'SomeObject'
Run Code Online (Sandbox Code Playgroud)
知道为什么吗?
更新:这是SomeObject的定义
class SomeObject
{
void operator=(const SomeObject&);
SomeObject(const SomeObject&);
public:
SomeObject()
{
// etc
}
// members snipped
}
Run Code Online (Sandbox Code Playgroud) 我有一个具有相当复杂的静态初始化的类.我正在从目录中读取文件,然后解析这些json文件,映射到对象,并填写列表.你可以想象,可能会出现一些异常,我需要覆盖并测试这些代码分支.问题是这个静态初始化只运行一次/ Testcase文件.解决方案我喜欢:
我对这些选项并不着迷,有什么更好的吗?
在Java中,我可以创建一个List并立即使用静态初始化程序填充它.像这样的东西:
List <String> list = new ArrayList<String>()
{{
Add("a");
Add("b");
Add("c");
}}
这很方便,因为我可以动态创建列表,并将其作为参数传递给函数.像这样的东西:
printList(new ArrayList<String>()
{{
Add("a");
Add("b");
Add("c");
}});
我是C#的新手,并试图弄清楚如何做到这一点,但我是空洞的.这可能在C#中吗?如果是这样,怎么办呢?
我正在尝试使用相同的初始化程序初始化大量元素.64个元素只是一个例子 - 我想让它至少达到16k.不幸的是简单
let array : [AllocatedMemory<u8>; 64] = [AllocatedMemory::<u8>{mem:&mut []};64];
Run Code Online (Sandbox Code Playgroud)
因为AllocatedMemory结构没有实现,所以不起作用Copy
error: the trait `core::marker::Copy` is not implemented for the type `AllocatedMemory<'_, u8>` [E0277]
let array : [AllocatedMemory<u8>; 64] = [AllocatedMemory::<u8>{mem:&mut []}; 64];
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
所以我尝试使用宏无济于事:
struct AllocatedMemory<'a, T: 'a> {
mem: &'a mut [T],
}
macro_rules! init_memory_helper {
(1, $T : ty) => { AllocatedMemory::<$T>{mem: &mut []} };
(2, $T : ty) => { init_memory_helper!(1, $T), init_memory_helper!(1, $T) };
(4, $T : ty) => { init_memory_helper!(2, …Run Code Online (Sandbox Code Playgroud) 我正在尝试初始化静态最终变量。但是,此变量是在可能引发异常的方法中初始化的,因此,我需要在try catch块内使用。
即使我知道变量将在try或catch块上初始化,Java编译器也会产生错误
最终字段a可能已经分配
这是我的代码:
public class TestClass {
private static final String a;
static {
try {
a = fn(); // ERROR
} catch (Exception e) {
a = null;
}
}
private static String fn() throws Exception {
throw new Exception("Forced exception to illustrate");
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试了另一种方法,直接将其声明为null,但它显示了类似的错误(在这种情况下,对我来说似乎完全合乎逻辑)
无法分配最终字段TestClass.a
public class TestClass {
private static final String a = null;
static {
try {
a = fn(); // ERROR
} catch (Exception e) {
}
}
private static String …Run Code Online (Sandbox Code Playgroud) java中程序的入口点通常是这样的
// MyMain.java
public class MyMain{
//whatever
public static void main(String args[]){
System.out.println("balderdash");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,由于main中只有一个SOP,因此上述类可能是这样的
// MyMain.java
public class MyMain{
//whatever
static {
System.out.println("balderdash");
}
}
使用main(...)的一个明显优点是参数可以传递给程序.另一个(我在这里猜测)可能与垃圾收集器有关,不同地处理在静态块中创建的对象.
使用语言定义的入口点还有其他好处 - public static void main(String args [])而不是使用静态初始化程序.
ps上述代码段仅供参考,可能无法编译
我正在为我和其他几个人写的程序进行本地化.现在大多数字符串都是从ini文件中以适当的语言加载的.我试图用程序中的货币格式做同样的事情.但是,一旦我尝试启动应用程序,我就会收到运行时异常.
我正在使用Locale对象作为一些NumberFormat.getCurrencyInstance()的参数,如下所示:
private static final NumberFormat decf;
static
{
decf = NumberFormat.getCurrencyInstance(Lang.cLocale);
decf.setRoundingMode(RoundingMode.HALF_UP);
}
Run Code Online (Sandbox Code Playgroud)
Lang是包含所有本地化内容的类.IDE在尝试运行时抱怨的代码是public static Locale cLocale = new Locale(GUI.DB_info[19],GUI.DB_info[20]);
GUI是包含GUI的类,我们决定构建DB_info数组(它本身只包含从另一个类的远程数据库加载的信息).DB_info [19]是语言代码(现在是),DB_info [20]是国家代码(US).数组元素正在被填充 - 或者说,我现在无法进入该程序; 但填充DB_info的代码没有任何改变.
完整的例外情况如下:
Exception in thread "main" java.lang.ExceptionInInitializerError
at greetingCard.GUI.<clinit>(GUI.java:118)
Caused by: java.lang.NullPointerException
at java.util.Locale.<init>(Unknown Source)
at java.util.Locale.<init>(Unknown Source)
at greetingCard.Lang.<clinit>(Lang.java:13)
... 1 more
Run Code Online (Sandbox Code Playgroud)
引用的GUI中的行是:static String welcome = Lang.L_WELCOME + ", " + empName;,而Lang.java基本上是这样的:
// Set locale for currency display
public static Locale cLocale = new Locale(GUI.DB_info[19],GUI.DB_info[20]); // language, country
// Employee …Run Code Online (Sandbox Code Playgroud) 我有一个指向函数的静态数组指针作为类的成员.
我需要对它进行初始化,但事实证明这个数组的长度是64K项,因此使用静态初始化器初始化它是不切实际的,就像{ x, y, z, ... }它会使代码混乱一样.
我反而用代码初始化它,有几个循环.
我想要这样做的方法是static在构造函数中初始化数组并为其设置一个标志,因此只有该类的第一个实例的构造才会触发此初始化.
从实例中访问这个静态标志也不是线程安全的,但这是另一个故事.
有更干净或更好的方法吗?
我也想要这个数组const,但我担心唯一的方法就是static {}初始化,对吗?
在《清洁代码》一书中有一个我想更好地理解的例子:
public static SimpleDateFormat makeStandardHttpDateFormat() {
// SimpleDateFormat is not thread safe, so we need to create each instance independently
SimpleDateFormat df = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df
}
Run Code Online (Sandbox Code Playgroud)
我读到这SimpleDateFormat不是线程安全的,因为它:将中间结果存储在实例字段中。因此,如果一个实例被两个线程使用,它们可能会弄乱彼此的结果。现在我感兴趣的是为什么使用静态工厂方法是避免此类SimpleDateFormat非线程安全类的线程安全问题的一种解决方案(可能不是最好的)?
如果我们有两个线程 A 和 B,为什么创建makeStandardHttpDateFormat()静态方法会有帮助呢?makeStandardHttpDateFormat()如果不是静态的,因为我们为每个线程创建了无论如何的新实例,那不是一样吗SimpleDateFormat?
书中指出
……这个评论是完全合理的。它将防止一些过于急切的程序员以效率的名义使用静态初始化程序。
静态方法真的那么慢吗?这句话是什么意思呢?为什么仅仅因为注释就应该阻止“过于热切的程序员”使用这个静态方法?IDE 可能甚至不会显示注释。但是,它可能会表明该方法是静态的。所以对我来说这个评论毫无意义。至少,不像书中提到的那样。
java ×8
c++ ×2
c# ×1
constructor ×1
entry-point ×1
final ×1
jls ×1
junit ×1
locale ×1
object ×1
rust ×1
static ×1
static-array ×1
struct ×1