Java应该将数组视为对象吗?

时间:2009-02-18 03:53:35

标签: java arrays

我经常认为允许使用数组作为适当的对象使用自己的方法而不是依赖于Arrays,Arrays和ArrayUtils等辅助类是个好主意。

例如:

ints.sort();                 // Arrays.sort(ints);
int[] onemore = ints.add(8); // int[] onemore = ArrayUtils.add(ints, 8);

我确信我不是第一个有这个想法的人,但是我很难找到其他之前写过这个想法的人。任何人都可以帮我提一些关于这个主题的参考资料吗?

这被认为是好主意还是坏主意?为什么?

实施起来有多容易?

其他一些例子可能包括(但不要挂断它们,它们与问题本身无关):

int[] ints = {5,4,3,2,1};

// Arrays.sort (ints);
ints.sort();

// int pos = Arrays.asList(ints).indexOf (5);
// int pos = ArraysUtils.indexOf (ints, 5);
int pos = ints.indexOf (5);

// Arrays.reverse (ints);
ints.reverse();

Array<Integer> array = ints; // cast to super class.

// int length = Array.getLength (array);
int length = array.getLength();

// Object n = Array.get (array, 3);
Object n = array.get (3);

// Array.set (array, 3, 7);
array.set (3, 7);

Object obj = array;
// if (obj instanceof int[])
//     System.out.println(Array.toString((int[]) obj));
// else if (....)
System.out.println (obj);

10 个答案:

答案 0 :(得分:7)

数组不是Java中的类,这是有充分理由的 - 它们很好地映射了人们对数组如何使用C风格语言的经验的理解。制作数组低级容器而不是对象也有性能原因。因此,有时使用基本数组而不是集合会带来性能优势。

如果要使用对象,则应使用Collection(ArrayList是集合的示例)。它可能很笨重,但Collections提供了你似乎想要的一种很好的方法访问。

答案 1 :(得分:5)

这些方法开始看起来非常像ruby或python习语。不幸的是你不能在java中做到这一点(希望你能)。

正如其他人所指出的那样,集合类为你做了。另一方面,myarray.sort()不太好,因为您可以创建尚未定义排序的对象数组。假设我有

 Foo[] foos; 

Foo不是可比的。 foos.sort()会发生什么?我们绝对不希望它只适用于原语

int[] ints; 
ints.sort(); //legal
Object[] objects;
objects.sort(); //illegal

并且你当然不能让编译器只允许类似对象的语法。一旦你得到像

这样的东西
 myarray.add(new Foo());

它有点无意义,因为java中的数组不可增长。

如果打印出一个数组并没有给你那么无用很好

([I'm an array(*&(*
但是,垃圾。

答案 2 :(得分:3)

是。但我认为 Java根本不应该有任何原语。我认为Java中的原语是对语言清晰度的打破。 Java中的所有东西都应该是对象。 是否在堆栈上分配对象应该是JVM的实现详细信息而不是语言结构。但我认为我的观点可能比大多数人更激进。

在自动装箱之前,处理原语和对象非常麻烦。

如果数组是对象并且可以自动装帧(并且是通用的!),我们可能会有类似的东西

Array<Integer> myArray = new Integer[];
myArray.add(8);
int x = myArray[0];
....

Array<Class<? extends MyBaseObject>> myArray = {ExtendedObject.class}
ExtendedObject object = myArray[0].newInstance();
....

答案 3 :(得分:2)

在我回答之前,我会告诉你这个问题的状态。

在Java中,数组被视为对象 - 例如,您可以将它们存储在List中。但是它们是特殊对象,因为它们从Object继承但未实例化或使用相同的语法访问(感谢更正Peter)。它们由JVM积极优化以解决明显的性能问题,因此存储数组的方式取决于实现。

所以Sun的论点是,如果他们为数组提供了一个对象API,它可能需要某些硬件,软件或其他规范功能。

数组唯一真正的接口是System.arrayCopy静态方法或Array。*静态方法,它们可以最有效地复制到数组中或从数组中复制。

回应应该;它已经解决了,虽然标准会比答案更好:使用ArrayList。

答案 4 :(得分:2)

是的,我相信数组应该定义超出语言本身指定的API。特别是,Foo[]未实现Iterable<Foo>令人讨厌。是的,我知道它很容易包装 - 但是你必须这很烦人。

.NET大体上是正确的,Array类型主要用于非泛型访问,以及各种通用接口,它们被认为是由实际数组实现的。例如:

IList<int> intList = new int[10];

(这有助于.NET泛型比Java更好地处理原始类型。)

我看到这种方法的唯一缺点是,数组在.NET中可以是协变的,但普通的泛型不是,而且基于非零的数组和矩形数组会让事情变得有些混乱。

顺便说一句,不同的人在这个帖子中将数组称为基元。虽然他们肯定有特殊处理,但他们并没有被定义为原始人。来自language spec, section 4.2

  

原始类型由Java编程语言预定义并由其命名   保留关键字(§3.9):

PrimitiveType:
        NumericType
        boolean

NumericType:
        IntegralType
        FloatingPointType

IntegralType: one of
        byte short int long char

FloatingPointType: one of
        float double

答案 5 :(得分:1)

这不是 BAD 的想法。事情已经在集合上完成了。如果你想发疯,请尝试扩展ArrayList。

答案 6 :(得分:1)

我认为在不破坏多层次兼容性的情况下很难实现。

  • JVM与其他对象的处理方式略有不同。创建/初始化是不同的:没有为一件事调用构造函数。您想如何添加新方法?如果通过添加超类,你会调用它的构造函数吗?
  • 数组在运行时知道元素的类型,而泛型则不知道。如果你想为所有数组添加新的超类(就像你在原始问题中建议的那样),你会把它变成通用的吗?还要记住,数组在Java中是协变的,而泛型则不是。
  • 数组具有Java语言规范中指定的固定方法/字段集(来自Objects的所有方法,在JLS中明确命名,长度字段)。添加新成员可能会破坏现有客户端,具体取决于此。 (即数组不是你的随机类)
  • 阵列序列化也可能会受到影响
  • 我确信有更多的实施细节可能会使这个极其困难: - (
  • 编译为使用新方法的程序不适用于较旧的JVM。更糟糕的是,根据实现情况,为旧JVM编译的程序可能无法在新JVM上使用修改后的数组。

我想直接在“数组类”中使用方法,我认为现在不可能实现它。

答案 7 :(得分:1)

我个人喜欢将一切都作为对象的想法,例如,这已经在smalltalk中完成了。然而,使一切,甚至方法/功能成为一个对象的后果是非常深远的(看看smalltalk看看我的意思)。在“一切都是对象”的应用中保持一致 - 规则导致一种看起来不再像C(或Java)的语言。

Java非常有意识地设计为可以接近C程序员,并且它已经取得了成功,但与smalltalk相比,它实际上并不是面向对象的。它是一种传统,因为C变体遍布整个地方,就像阵列和存在基元的事实一样。

所以为了回答SHOULD的问题,我会说不,因为随着这种变化,Java将不再是Java。正如其他人已经指出的那样,还有其他类允许你使用Java中的对象处理可能用C中的数组完成的任务,但是要完全摆脱原始数据类型和数组是一个更好的留给不同语言的任务,恕我直言。

答案 8 :(得分:0)

对于错过之前关闭的帖子的人。其他一些例子包括

int[] ints = {5,4,3,2,1};
ints.sort(); // instead of Arrays.sort(ints);
int pos = ints.indexOf(5); // instead of Arrays.asList(ints).indexOf(5); or ArraysUtils.indexOf(ints, 5);
ints.reverse(); // instead of Arrays.reverse(ints);
Array<Integer> array = ints; // cast to super class.
int length = array.getLength(); // instead of Array.getLength(array);
Object n = array.get(3); // instead of Array.get(array, 3);
array.set(3, 7); // instead of Array.set(array, 3, 7);
Object obj = array;
System.out.println(obj); // prints [5,4,7,2,1] instead of having to
// if (obj instanceof int[]) System.out.println(Array.toString((int[]) obj)); else if (....)

int[] ints2 = ints.copyOf(2);
int[] ints3 = ints.subArray(2,4);
ints.sort(myComparator);
List<Integer> list = ints.asList();
Set<Integer> set = ints.asSet();
long total = ints.sum();
double avg = int.average();
int max = ints.max();
int max2 = ints.max(myComparator);
http://commons.apache.org/lang/api/org/apache/commons/lang/ArrayUtils.html
int[] onemore = ints.add(8); // instead of ArrayUtils.add(ints, 8);
int[] moreInts = ints.addAll(ints2); // instead of ArraysUtils.addAll(ints, ints2);
int[] oneless = int.remove(3); // instead of ArrayUtils.remove(ints, 3);
Integer[] integers = int.toObject();
int[] intsAgain = integers.toPrimitive();

答案 9 :(得分:0)

我相信它不会那么难的一个原因是你可以通过修改Object来间接添加方法(真正的黑客我同意,但它表明它有效) 通过向Object添加方法,可以使用以下代码

int[] ints = {5, 4, 3, 2, 1};
System.out.println("ints= "+ints);
ints.sort();
System.out.println("after sort() ints= "+ints);
ints = ints.add(6);
System.out.println("after add(6) ints= "+ints);

打印

ints= [5, 4, 3, 2, 1]
after sort() ints= [1, 2, 3, 4, 5]
after add(6) ints= [1, 2, 3, 4, 5, 6]

这适用于Java 5&amp; 6,编译器和IDE都按照我的预期处理了这个。