当前位置: 首页 > 面试题库 >

Java N-Tuple实现

慕弘伟
2023-03-14
问题内容

我只是做了一个Java n元组,它是类型安全的。
我正在使用一些非常规的方法来实现类型安全(我只是为了好玩而已)。

有人可以提供一些改进建议或一些可能的缺陷。

public class Tuple {
    private Object[] arr;
    private int size;
    private static boolean TypeLock = false;
    private static Object[] lastTuple = {1,1,1}; //default tuple type

    private Tuple(Object ... c) {
        // TODO Auto-generated constructor stub
        size=c.length;
        arr=c;
        if(TypeLock)
        {
            if(c.length == lastTuple.length)
                for(int i = 0; i<c.length; i++)
                {
                    if(c[i].getClass() == lastTuple[i].getClass())
                        continue;
                    else
                        throw new RuntimeException("Type Locked");
                }
            else
                throw new RuntimeException("Type Locked");
        }

        lastTuple = this.arr;
    }

    public static void setTypeLock(boolean typeLock) {
        TypeLock = typeLock;
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if (this == obj)
            return true;

        Tuple p = (Tuple)obj;

        for (int i = 0; i < size; i++)
        {
            if (p.arr[i].getClass() == this.arr[i].getClass())
            {
                if (!this.arr[i].equals(p.arr[i]))
                    return false;
            }
            else
                return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        int res = 17;
        for(int i = 0; i < size; i++)
            res = res*37+arr[i].hashCode();

        return res;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return Arrays.toString(arr);
    }

    public static void main(String[] args) {
        HashMap<Tuple,String> birthDay = new HashMap<Tuple,String>();
        Tuple p = new Tuple(1,2,1986);
        Tuple.setTypeLock(true);
        Tuple p2 = new Tuple(2,10,2009);
        Tuple p3 = new Tuple(1,2,2010);
        Tuple p4 = new Tuple(1,2,2010);
        birthDay.put(p,"Kevin");
        birthDay.put(p2,"Smith");
        birthDay.put(p3,"Sam");
        birthDay.put(p4, "Jack");
        System.out.println(birthDay);
        System.out.println(birthDay.get(new Tuple(1,2,1986)));
        birthDay.put(new Tuple(1,2,""),"");
    }
}

问题答案:

在做中学的荣誉。以下是“机会”有待改进的建议:

  1. 元组只能存在一种(一旦设置了Typelock)。除非您诉诸于剪切粘贴重复使用(BirthdayTuple,DimensionsTuple,StreetAddressTuple等),否则这会损害希望使用多种元组类型的程序的可重用性和可伸缩性。考虑一个TupleFactory类,该类接受目标类型并创建一个元组生成器对象以生成元组。

  2. 没有记录“ null”作为元组中的值的有效性。我认为在设置Typelock之前,允许为null;但是设置了Typelock之后,代码将生成NullPointerException-这是不一致的。如果不允许使用,则构造函数应捕获它并禁止它(与Typelock无关)。如果允许,则整个代码(构造函数,equals,hashcode等)都需要进行修改以允许使用。

  3. 确定元组是否旨在成为不可变值对象。基于它缺乏设置方法的原因,我猜是这样。如果是这样,请小心“采用”传入的数组- lastTuple=this.arr。即使其为var arg构造函数,也可以直接使用数组调用该构造函数。该类采用数组(保留对其的引用),并且此后可以在类外部更改数组中的值。我将对数组进行浅表复制,但还要记录具有不可更改值(可以在元组外部更改)的元组的潜在问题。

  4. 您的equals方法缺少空检查(if (obj == null) return false)和类检查(obj instanceof Tuplethis.getClass().equals(object.getClass()))。平等习语有据可查。

  5. 除非通过,否则无法查看元组的值toString。这样可以保护的值和整体不变性,但是我认为这限制了该类的用处。

  6. 虽然我意识到这只是一个例子,但我不希望将此类用于生日/日期之类的东西。在具有固定对象类型的解决方案域中,真实类(例如Date)要好得多。我可以想象此类在元组是第一类对象的特定领域中很有用。

编辑
一直在考虑这一点。这是我对一些代码的看法(在github
+
tests上):

===
Tuple.java
===
package com.stackoverflow.tuple;

/**
 * Tuple are immutable objects.  Tuples should contain only immutable objects or
 * objects that won't be modified while part of a tuple.
 */
public interface Tuple {

    public TupleType getType();
    public int size();
    public <T> T getNthValue(int i);

}


===
TupleType.java
===
package com.stackoverflow.tuple;

/**
 * Represents a type of tuple.  Used to define a type of tuple and then
 * create tuples of that type.
 */
public interface TupleType {

    public int size();

    public Class<?> getNthType(int i);

    /**
     * Tuple are immutable objects.  Tuples should contain only immutable objects or
     * objects that won't be modified while part of a tuple.
     *
     * @param values
     * @return Tuple with the given values
     * @throws IllegalArgumentException if the wrong # of arguments or incompatible tuple values are provided
     */
    public Tuple createTuple(Object... values);

    public class DefaultFactory {
        public static TupleType create(final Class<?>... types) {
            return new TupleTypeImpl(types);
        }
    }

}


===
TupleImpl.java (not visible outside package)
===
package com.stackoverflow.tuple;

import java.util.Arrays;

class TupleImpl implements Tuple {

    private final TupleType type;
    private final Object[] values;

    TupleImpl(TupleType type, Object[] values) {
        this.type = type;
        if (values == null || values.length == 0) {
            this.values = new Object[0];
        } else {
            this.values = new Object[values.length];
            System.arraycopy(values, 0, this.values, 0, values.length);
        }
    }

    @Override
    public TupleType getType() {
        return type;
    }

    @Override
    public int size() {
        return values.length;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getNthValue(int i) {
        return (T) values[i];
    }

    @Override
    public boolean equals(Object object) {
        if (object == null)   return false;
        if (this == object)   return true;

        if (! (object instanceof Tuple))   return false;

        final Tuple other = (Tuple) object;
        if (other.size() != size())   return false;

        final int size = size();
        for (int i = 0; i < size; i++) {
            final Object thisNthValue = getNthValue(i);
            final Object otherNthValue = other.getNthValue(i);
            if ((thisNthValue == null && otherNthValue != null) ||
                    (thisNthValue != null && ! thisNthValue.equals(otherNthValue))) {
                return false;
            }
        }

        return true;
    }

    @Override
    public int hashCode() {
        int hash = 17;
        for (Object value : values) {
            if (value != null) {
                hash = hash * 37 + value.hashCode();
            }
        }
        return hash;
    }

    @Override
    public String toString() {
        return Arrays.toString(values);
    }
}


===
TupleTypeImpl.java (not visible outside package)
===
package com.stackoverflow.tuple;

class TupleTypeImpl implements TupleType {

    final Class<?>[] types;

    TupleTypeImpl(Class<?>[] types) {
        this.types = (types != null ? types : new Class<?>[0]);
    }

    public int size() {
        return types.length;
    }

    //WRONG
    //public <T> Class<T> getNthType(int i)

    //RIGHT - thanks Emil
    public Class<?> getNthType(int i) {
        return types[i];
    }

    public Tuple createTuple(Object... values) {
        if ((values == null && types.length == 0) ||
                (values != null && values.length != types.length)) {
            throw new IllegalArgumentException(
                    "Expected "+types.length+" values, not "+
                    (values == null ? "(null)" : values.length) + " values");
        }

        if (values != null) {
            for (int i = 0; i < types.length; i++) {
                final Class<?> nthType = types[i];
                final Object nthValue = values[i];
                if (nthValue != null && ! nthType.isAssignableFrom(nthValue.getClass())) {
                    throw new IllegalArgumentException(
                            "Expected value #"+i+" ('"+
                            nthValue+"') of new Tuple to be "+
                            nthType+", not " +
                            (nthValue != null ? nthValue.getClass() : "(null type)"));
                }
            }
        }

        return new TupleImpl(this, values);
    }
}


===
TupleExample.java
===
package com.stackoverflow.tupleexample;

import com.stackoverflow.tuple.Tuple;
import com.stackoverflow.tuple.TupleType;

public class TupleExample {

    public static void main(String[] args) {

        // This code probably should be part of a suite of unit tests
        // instead of part of this a sample program

        final TupleType tripletTupleType =
            TupleType.DefaultFactory.create(
                    Number.class,
                    String.class,
                    Character.class);

        final Tuple t1 = tripletTupleType.createTuple(1, "one", 'a');
        final Tuple t2 = tripletTupleType.createTuple(2l, "two", 'b');
        final Tuple t3 = tripletTupleType.createTuple(3f, "three", 'c');
        final Tuple tnull = tripletTupleType.createTuple(null, "(null)", null);
        System.out.println("t1 = " + t1);
        System.out.println("t2 = " + t2);
        System.out.println("t3 = " + t3);
        System.out.println("tnull = " + tnull);

        final TupleType emptyTupleType =
            TupleType.DefaultFactory.create();

        final Tuple tempty = emptyTupleType.createTuple();
        System.out.println("\ntempty = " + tempty);

        // Should cause an error
        System.out.println("\nCreating tuple with wrong types: ");
        try {
            final Tuple terror = tripletTupleType.createTuple(1, 2, 3);
            System.out.println("Creating this tuple should have failed: "+terror);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace(System.out);
        }

        // Should cause an error
        System.out.println("\nCreating tuple with wrong # of arguments: ");
        try {
            final Tuple terror = emptyTupleType.createTuple(1);
            System.out.println("Creating this tuple should have failed: "+terror);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace(System.out);
        }

        // Should cause an error
        System.out.println("\nGetting value as wrong type: ");
        try {
            final Tuple t9 = tripletTupleType.createTuple(9, "nine", 'i');
            final String verror = t9.getNthValue(0);
            System.out.println("Getting this value should have failed: "+verror);
        } catch (ClassCastException ex) {
            ex.printStackTrace(System.out);
        }

    }

}

===
Sample Run
===
t1 = [1, one, a]
t2 = [2, two, b]
t3 = [3.0, three, c]
tnull = [null, (null), null]

tempty = []

Creating tuple with wrong types: 
java.lang.IllegalArgumentException: Expected value #1 ('2') of new Tuple to be class java.lang.String, not class java.lang.Integer
    at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:32)
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:37)

Creating tuple with wrong # of arguments: 
java.lang.IllegalArgumentException: Expected 0 values, not 1 values
    at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:22)
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:46)

Getting value as wrong type: 
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:58)


 类似资料:
  • 头文件: "boost/tuple/tuple.hpp" 它包含了 tuple 类模板及库的核心部分。 Header: "boost/tuple/tuple_io.hpp" 包含了对 tuple 的输入输出操作符。 Header: "boost/tuple/tuple_comparison.hpp" 包含了 tuple 的关系操作符。 Tuple 库位于 boost 里的嵌套名字空间 boos

  • 解释tuple 元组的意思 tuple名字叫做元组, name = ( "number1", "number2", "number3" ) 它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的,你可以正常地使用classmates[0],classmates[-1],但不能赋值成另外的元素。 不可变的tuple有什么意义?因为tuple不可变,所以代码更安全

  • 描述 (Description) 方法tuple()将项列表转换为元组 语法 (Syntax) 以下是tuple()方法的语法 - tuple( seq ) 参数 (Parameters) seq - 这是一个要转换为元组的序列。 返回值 (Return Value) 此方法返回元组。 例子 (Example) 以下示例显示了tuple()方法的用法。 #!/usr/bin/python aLi

  • 描述 (Description) 方法min()以最小值返回元组中的元素。 语法 (Syntax) 以下是min()方法的语法 - min(tuple) 参数 (Parameters) tuple - 这是一个元组,从中返回最小值元素。 返回值 (Return Value) 此方法以最小值返回元组中的元素。 例子 (Example) 以下示例显示了min()方法的用法。 #!/usr/bin/p

  • 描述 (Description) 方法max()以最大值返回元组中的元素。 语法 (Syntax) 以下是max()方法的语法 - max(tuple) 参数 (Parameters) tuple - 这是一个元组,从中返回最大值元素。 返回值 (Return Value) 此方法返回元组中具有最大值的元素。 例子 (Example) 以下示例显示了max()方法的用法。 #!/usr/bin/

  • 描述 (Description) 方法len()返回元组中元素的数量。 语法 (Syntax) 以下是len()方法的语法 - len(tuple) 参数 (Parameters) tuple - 这是一个元组,要计算的元素数量。 返回值 (Return Value) 此方法返回元组中的元素数。 例子 (Example) 以下示例显示len()方法的用法。 #!/usr/bin/python t