Java: универсальные статические многомерные массивы

Если это возможно, как я могу создать статический многомерный массив в Java с разными примитивными типами данных на измерение?

Под статическим я подразумеваю примитивный массив, который не является динамическим, как ArrayList.

5 ответов

Решение

Размеры в массиве всегда относятся к типу int. Думаю об этом!

int a = 4;
int b = 5;

Shoe shoe = new Shoe (Color.RED, 42, "Leather");
Hat hat = new Hat (17, Color.Black);

Foo foo = foos[a][b];
Zilch pop = bars[shoe][hat]; // no go

Если у вас есть многомерный массив Foos, первое измерение - это Foo, второе - массив Foos, третье - массив массива Foo. Единственный тип переменной - тот, что внизу.

Изменить после обновления вопроса:

Массивы не называются статическими или примитивными. Их размер фиксируется при инициализации, и они имеют общее с примитивами в том, что они являются buildin, что в некоторых случаях представляет особую опасность. Они - в отличие от так называемых примитивных типов, которые не являются такими примитивными (например, у них есть операторы исключительно для своих * / -) но пока что они являются объектами, но не объявлены в библиотеке.

Позвони им build in-types,

Используя трюк Беш Гурунг:

Object[] arr = {new Integer[]{}, new String[]{}, new Double[]{}}; 

напрашивается на неприятности, и он не состоит из разных типов данных в измерении. Начнем с размеров:

// One-dimensional object:
JPanel [] panels = new JPanel [3]; 
// Two-dimensional object:
JPanel [][] panels = new JPanel [3][10]; 

У вас есть JPanels на нижнем уровне и массив JPanel на следующем измерении. Вы можете добавить больше измерения, и всегда получите дополнительный (Array of ...) обернутый вокруг.

Вы не можете смешивать различные типы данных в массиве, такие как int и char, или JPanel и JFrame, или int и JButton. Только если вы абстрагируетесь от разницы и используете JComponent для JPanel и JFrame в качестве общего родителя, но это не будет работать для встроенных типов int, char, boolean и т. Д., Поскольку они не являются объектами.

Но нельзя ли использовать автобокс и использовать Integer вместо int, Character вместо char, а затем использовать Object в качестве общего родительского класса? Да, вы могли бы, но тогда вы больше не используете примитивы и просите неприятностей.

Дэн говорит о другом - использует разные типы для индексации в многомерном массиве:

byte  b = 120;
short s = 1000;
String o [][] = new String[b][s];
b = 7;
s = 9;  
o[b][s] = "foobar";
String foo = o[b][s];

Нет проблем с использованием байтов или шортов, но вы не можете ограничить размер массива, объявив его байтовым или коротким. В большинстве случаев границы встроенного целочисленного типа не будут соответствовать типу данных (например, 365 дней в году), особенно, поскольку все типы могут становиться отрицательными, поэтому проверка границ необходима, хотя и не может быть ограничена компиляцией время.

Но теперь к беде
Мы могли бы объявить массив как двумерный с самого начала:

Object[][] ar2 = {
    new Integer [] {4, 5, 6}, 
    new String [] {"me", "and", "you"}, 
    new Character [] {'x', 'y', 'z'}};

Это прекрасно работает, и делает внутренние массивы доступными сразу, без приведения. Но компилятору известно только то, что элементы являются массивами объектов - базовый тип абстрагируется, и поэтому мы можем написать:

ar2[1][1] = 17; // expected: String
ar2[2][0] = "double you"; // expected: Char

Это скомпилируется без ошибок, но вы стреляете себе в ногу и получаете исключение Runtime бесплатно.

Вот источник в целом:

public class ArrOfMixedArr
{
    public static void main (String args[])
    {
        Object[] arr = {
            new Integer [] {1, 2, 3}, 
            new String [] {"you", "and", "me"}, 
            new Character [] {'a', 'b', 'c'}};
        show (arr);

        byte b = 7;
        short s = 9;
        String o [][] = new String[200][1000];
        o[b][s] = "foobar";
        String foo = o[b][s];

        Object[][] ar2 = {
            new Integer [] {4, 5, 6}, 
            new String [] {"me", "and", "you"}, 
            new Character [] {'x', 'y', 'z'}};
        show (ar2);

        // exeptions:
        ar2[1][1] = 17; // expected: String
        ar2[2][0] = "double you"; // expected: Char
    }

    public static void show (Object[] arr)
    {
        for (Object o : arr) 
        {
            if (o instanceof Object[])
                show ((Object[]) o);
            else 
                System.out.print (o.toString () + "\t");
        }
        System.out.println ();
    }
}

Теперь, каково решение? Если ваши массивы базовых типов (int, byte, char, String, JPanel, ...) имеют одинаковую длину, то у вас есть что-то вроде скрытого объекта, строки базы данных. Вместо этого используйте класс:

class Shoe {
    byte size;
    String manufactor;
    java.math.BigDecimal price;
    java.awt.Color color;
}

Shoe [] shoes = new Shoe [7];

Если у вас нет разных типов одинакового размера, они могут быть не связаны и не должны быть помещены в общий контейнер.

Ты не можешь

Многомерный массив по определению является массивом массивов массивов... чего-либо. Таким образом, ни одно из этих измерений, кроме последнего, не может быть чем-либо, кроме массива. По крайней мере, по традиционному определению. Но если вы имеете в виду что-то еще под "многомерным массивом", вам нужно будет сказать нам, что это такое.

Что касается "статического", это слово сильно перегружено в программировании, и каждый язык, который я могу придумать, использует его для обозначения чего-то немного другого. В Java static означает "принадлежит классу, а не экземплярам этого класса". Опять же, если вы подразумеваете что-то еще под "статичным" здесь, вам нужно будет сказать нам, что это такое.

Изменить: как первоначально опубликовано, вопрос не включал слово "примитив". Это немного меняет это. Действительно, я согласен, что было бы неплохо с точки зрения удобства, если бы Java позволяла индексировать массивы char или даже enum а не просто int, Но это не так.

После некоторого тестирования у меня есть простое решение:

Object [][] array = new Object [10][2];
array[0][0] = 2;
array[0][1] = false;

Вы можете получить эффект, используя массив объектов:

final static Object tryit[][] = {
        {'a',4},
        {'b',7},
        {'c',8},
};
@Test
public void accessArray( ) {
    for (int i = 0; i < tryit.length ; i++) {
        char letter = (Character)tryit[i][0];
        int value = (Integer)tryit[i][1];
        System.out.println(letter + " has value " + value);
    }
}

@Test - это аннотация JUnit.

Обратите внимание, что этот подход будет подвергаться исключениям NullPointer и ClassCast во время выполнения, если в массив введены неправильные данные.

Ну, вы могли бы определить массив из массива... массив объектов (вложенных с таким количеством уровней, сколько измерений) и на нижнем уровне заполнить каждый массив с другим типом... и затем, когда вам нужно извлечь значение, приведите его к соответствующему типу. Слишком много работы ради чего стоит, правда. Java не годится для такого рода вещей, поскольку является языком статической типизации.

Может быть, вам следует пересмотреть, зачем вам такая структура данных.

Другие вопросы по тегам