我正在用Java编写一个Lisp解释器,而且我对语言中的泛化性有点担心。我有一个类List
,其定义如下:
public class List<E extends Lisp> implements Lisp {
private ArrayList<E> list = new ArrayList<>();
List(){
/* Constructor code goes here */
}
/*
Other methods that deal with lists go here
*/
}
Lisp只是一个接口,我用它作为Lisp,Atoms和Lists中两种类型的共同点。由于Lisp中的列表可以指向更多列表以及Atoms,因此我需要能够通过通用性将列表存储到列表中,这意味着ArrayList
需要能够保存类型为{{1}的对象}和List
类型的对象。当我尝试提取列表的第一个成员时出现问题,理论上它可以是列表或原子,但我可以拥有两个具有相同名称并返回不同类型的函数。因此,我想到的解决方法是:
Atom
我的想法是,如果存储的对象是public E car(List<E> l) {
if (l.list.get(0) instanceof Atom)
return (E)(Atom) l.list.get(0);
else
return (E)(List<E>) l.list.get(0);
}
类型,将其转换为Atom
然后再转换为通用对象E,是否有其他方法解决此问题?
另一个问题是,在方法Atom
中,重载时有两个定义,一个看起来像这样:
cons
和另一个看起来像这样:
public List<E> cons(List<E> l1, List<E> l2)
口译员/编制者似乎认为 public List<E> cons(Atom a, List<E> l) {
List<E> cons_list = new List<E>();
cons_list.list.add(a);
cons_list.list.addAll(l.list);
return cons_list;
}
不包括E
。有没有解决这个问题? eclipse报告的错误是:
类型ArrayList中的方法add(E)不适用于 参数(Atom)
答案 0 :(得分:2)
解释器/编译器似乎认为E不包括Atom。有没有解决这个问题?
在编译时,您的程序无意知道E
是Atom
。必须通过另一个类测试才能使它工作:
public List<E> cons(E a, List<E> l) {
List<E> cons_list = new List<E>();
if (a instanceof Atom) {
cons_list.list.add(a);
}
cons_list.list.addAll(l.list);
return cons_list;
}
这可以解决您的问题,因为您尝试将E
对象添加到List<E>
。
我的想法是,如果存储的对象是Atom类型,将其转换为Atom然后转换为通用对象E,还有其他方法解决此问题吗?
您的断言是正确的。这与我之前所说的问题相同:如果你试图将其强制转换为Atom
,那么只有你的编译器才会让你运行你的程序。但是,我认为你的演员选择是没用的:你有一个通用的对象,但是你在测试类时知道它是Atom
。我想你可以像这样减少你的方法:
public E car(List<E> l) {
if (l.list.get(0) instanceof Atom)
// Your `E` is an Atom, you know this when coming then
// Your list contains E's, so you don't have to cast it
return l.list.get(0);
else
// Here you need the double cast, because you don't try
// the actual class: it may be anything.
return (E)(List<E>) l.list.get(0);
}
另外,请注意ClassCastException
语句else
。您可以尝试使用List<E>
,尽管可以确定它可以是List
或Atom
。