我正在发布一个 different question 的答案,当我遇到一个小谜团。类定义(从原始发问者稍作修改)在这里:
public class Playground<T>{
private int pos;
private final int size;
private T[] arrayOfItems;
public Playground(int size){
this.size = size;
pos = 0;
arrayOfItems = (T[]) new Object[size];
}
public void addItem(T item) {
arrayOfItems[pos] = item;
pos++;
}
public void displayItems() {
for(int i = 0;i<pos;i++){
System.out.println(arrayOfItems[i]);
}
}
public T[] returnItems() {
return (T[]) arrayOfItems;
}
}
在 main 中,我们创建一个新的 Playground,Playground<String> animals = new Playground<String>(5);并在其中放一些动物线。 (狗、猫等)。
神秘的是这行得通:
Object[] s = animals.returnItems();
for(int i=0; i < s.length; i++) {
System.out.println(s[i]);
}
但这会创建一个 ClassCastException 在 for 循环声明中。
for(int i=0; i < animals.returnItems().length; i++) {
System.out.println(animals.returnItems()[i]);
}
两者都是 Object[] s 和 String[] s 有长度变量。为什么在循环声明中使用访问器方法会导致异常?
最佳答案
存在 ClassCastException 的原因-- 不能从 Object[] 转换至 String[] -- 是因为编译器在使用泛型时所做的事情。调用returnItems()时, 编译器将强制转换插入到 String[] ,因为 returnItems返回 T[] .编译时类型删除意味着它返回 Object[] , 但自 T是String在这里,编译器插入一个转换为 String[] .但是原始对象arrayOfItems不是 String[] , 这是一个 Object[] , 所以转换失败。
这应该会导致编译期间出现“未经检查的转换”警告,来自 Object[]至 T[] .
您需要做的是遵循 How to create a generic array in Java? 中的建议。在创建通用数组时。
接受 Class<T>在你的构造函数中,所以你可以调用 Array.newInstance得到 T[]从一开始。
@SuppressWarnings("unchecked") // This suppression is safe.
public Playground(int size, Class<T> clazz){
this.size = size;
pos = 0;
arrayOfItems = (T[]) Array.newInstance(clazz, size);
}
然后你可以创建animals通过 String.class :
Playground<String> animals = new Playground<String>(5, String.class);
更新
以下是关于为什么第一个示例有效(分配给 Object[])而第二个示例无效(直接根据 length 方法的返回类型访问字段 returnItems())的合理解释.
第一个例子
Object[] s = animals.returnItems();
for(int i=0; i < s.length;i++) {
System.out.println(s[i]);
}
JLS, Section 5.2 ,描述了“赋值上下文”,它管理将表达式的值赋给变量时发生的情况。
The only exceptions that may arise from conversions in an assignment context are:
- A ClassCastException if, after the conversions above have been applied, the resulting value is an object which is not an instance of a subclass or subinterface of the erasure (§4.6) of the type of the variable.
This circumstance can only arise as a result of heap pollution (§4.12.2). In practice, implementations need only perform casts when accessing a field or method of an object of parameterized type when the erased type of the field, or the erased return type of the method, differ from its unerased type.
...
编译器不需要向 String[] 插入强制转换这里。当 length稍后访问字段,变量已经是Object[]类型,所以这里没有问题。
第二个例子
for(int i=0; i < animals.returnItems().length;i++) {
System.out.println(animals.returnItems()[i]);
}
ClassCastException这里似乎不依赖于 for环形;简单打印长度会发生此错误:
System.out.println(animals.returnItems().length);
这是一个字段访问表达式,由JLS, Section 15.11.1 覆盖.
[T]he identifier names a single accessible member field in type T, and the type of the field access expression is the type of the member field after capture conversion (§5.1.10).
捕获转换捕获类型为String[] .编译器必须将强制转换插入到 String[]此处出于与为方法调用插入强制转换相同的原因 - 字段或方法可能仅存在于捕获的类型中。
因为 arrayOfItems 的类型真的是Object[] , 转换失败。
如上所述,使用 Array.newInstance 创建通用数组解决了这个问题,因为一个实际的 String[]正在创建。通过该更改,插入的类型转换仍然存在,但这次它成功了。
关于java - 数组返回可以用于赋值,但不能用于循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27989230/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这