2012-01-06 37 views
11

Tôi đang sử dụng Java 6.Làm thế nào để tôi có được một lớp bên trong để kế thừa kiểu chung của lớp kèm theo?

Tôi đang gặp khó khăn khi đưa lớp bên trong của mình sử dụng cùng một lớp chung chung như lớp kèm theo của nó. Hiện nay tôi có

public class TernarySearchTree <T> { 
    ... 
    protected class TSTNode <T> { 
     // index values for accessing relatives array 
     protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; 
     protected char splitchar; 
     protected TSTNode <T> [] relatives; 
     private T data; 

     protected TSTNode(char splitchar, TSTNode <T> parent) { 
      this.splitchar = splitchar; 
      relatives = new TSTNode[4]; 
      relatives[PARENT] = parent; 
     } 
    } 
} 

Ngay bây giờ tôi nhận được cảnh báo

Loại tham số T được giấu kiểu T

Nếu tôi loại bỏ các tham số kiểu từ lớp bên trong (tức là loại bỏ số <T> từ dòng teh protected class TSTNode<T>), sau đó tôi nhận được lỗi biên dịch trên dòng relatives = new TSTNode[4].

Làm cách nào để tôi có thể làm mọi thứ đúng?

+4

Nếu bạn gặp lỗi biên dịch, bạn nên ** include lỗi biên dịch tin nhắn trong câu hỏi của bạn! Nhưng nó hoạt động tốt cho tôi. Chỉ cần chắc chắn rằng bạn có được thoát khỏi '' trên * tờ khai * của 'người thân' là tốt. Điều đó nói rằng, bạn luôn có thể làm cho 'TSTNode' tĩnh và chỉ sử dụng một tham số khác, như' E'. –

+0

Tại sao không thể tạo mảng chung: http://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java –

+0

TSTNode có cần truy cập không trường mẫu hoặc phương thức từ TernarySearchTree? –

Trả lời

8

Bạn có thể:

  • loại bỏ các tham số <T> loại từ TSTNode (ví dụ, làm cho nó không chung chung) - nó sẽ vẫn có quyền truy cập vào bên ngoài <T>.

  • đổi tên thông số loại <T> trong lớp TSTNode thành (nói) U.

[UPDATE]

Dưới đây là bốn cách khác nhau để viết lại mã của bạn. Tất cả đều biên dịch. Tôi nghĩ bạn nên cân nhắc việc sử dụng một số EnumMap (xem Phiên bản 4 bên dưới).

Phiên bản 1: sử dụng thông số loại có tên khác biệt trong lớp bên trong. bạn cần sử dụng Danh sách thay vì mảng.

public class TernarySearchTree<T> { 

    protected class TSTNode<U> { 
     // index values for accessing relatives array: 
     protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; 

     protected char splitchar; 
     protected List<TSTNode<U>> relatives; 
     private U data; 

     protected TSTNode(char splitchar, TSTNode<U> parent) { 
     this.splitchar = splitchar; 
     relatives = new ArrayList<TSTNode<U>>(); 
     for (int i = 0; i < HIKID; ++i) { // Allocate 4 slots in relatives 
      relatives.add(null); 
     } 
     relatives.set(PARENT, parent); 
     }   
    } 

    private TSTNode<T> node; // When you use it, pass T as U 

    public TernarySearchTree() { 
     node = new TSTNode<T>(',', null); // When you use it, pass T as U 
    } 
    } 

Phiên bản 2: kế thừa T từ kèm theo lớp

public class TernarySearchTree<T> { 

    protected class TSTNode { 
     // index values for accessing relatives array: 
     protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; 

     protected char splitchar; 
     protected List<TSTNode> relatives; 
     private T data; 

     protected TSTNode(char splitchar, TSTNode parent) { 
     this.splitchar = splitchar; 
     relatives = new ArrayList<TSTNode>(); 
     for (int i = 0; i < HIKID; ++i) { // Allocate 4 slots in relatives 
      relatives.add(null); 
     } 
     relatives.set(PARENT, parent); 
     } 
    } 

    private TSTNode node; 

    public TernarySearchTree() { 
     node = new TSTNode(',', null); 
    } 
    } 

Phiên bản 3: sử dụng một bản đồ (thay vì một danh sách)

public class TernarySearchTree<T> { 

    protected class TSTNode { 
     // index values for accessing relatives array: 
     protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; 

     protected char splitchar; 
     protected Map<Integer, TSTNode> relatives; 
     private T data; 

     protected TSTNode(char splitchar, TSTNode parent) { 
     this.splitchar = splitchar; 
     // Create a hash map. No need to pre-allocate! 
     relatives = new HashMap<Integer, TSTNode>(); 
     relatives.put(PARENT, parent); // set -> put 
     } 
    } 

    private TSTNode node; 

    public TernarySearchTree() { 
     node = new TSTNode(',', null); 
    } 
    } 
} 

Version 4: xác định các chỉ mục dưới dạng enum + sử dụng EnunMap (thay vì một băm ma p)

public class TernarySearchTree<T> { 

    protected static enum Index { 
     PARENT, LOKID, EQKID, HIKID; 
    } 

    protected class TSTNode {  
     protected char splitchar; 
     protected EnumMap<Index, TSTNode> relatives; 
     private T data; 

     protected TSTNode(char splitchar, TSTNode parent) { 
     this.splitchar = splitchar; 
     // Create an EnumMap. 
     relatives = new EnumMap<Index, TSTNode>(Index.class); 
     relatives.put(Index.PARENT, parent); 
     } 
    } 

    private TSTNode node; 

    public TernarySearchTree() { 
     node = new TSTNode(',', null); 
    } 
    } 

[Cập nhật 2] Một điều cần lưu ý: Use EnumMap instead of ordinal indexing

+0

Giải pháp 1: Không biên dịch. –

+0

Giải pháp 2: T và U sẽ khác nhau và có thể anh ta muốn các loại chung giống nhau. –

+0

Tôi đã sử dụng giải pháp 4. Cảm ơn, - – Dave

2

Tôi không biết những gì bạn đang cố gắng để làm nhưng, có sollution này:

public class TernarySearchTree<T> { 

protected class TSTNode<E extends T> { 
    protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; 
    protected char splitchar; 
    protected TSTNode<E>[] relatives; 
    private E data; 

    protected TSTNode(char splitchar, TSTNode<E> parent) { 
     this.splitchar = splitchar; 
     relatives = new TSTNode[4]; 
     relatives[PARENT] = parent; 
    } 
} 
} 

Với điều này bạn nhận được một cảnh báo thay vì một lỗi ở cùng một dòng.

Sử dụng một danh sách có thể là một giải pháp tốt hơn (không có cảnh báo)

public class TernarySearchTree<T> { 

    protected class TSTNode<E extends T> { 
     protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; 
     protected char splitchar; 
     protected List<TSTNode<E>> relatives; 
     private E data; 

     protected TSTNode(char splitchar, TSTNode<E> parent) { 
      this.splitchar = splitchar; 
      relatives = new ArrayList<TSTNode<E>>(); 
      relatives.set(PARENT, parent); 
     } 
    } 
} 
0

tôi nghi ngờ những gì bạn muốn là một cái gì đó như:

class Tree<T> { 
    Node<T> head; 

    static class Node<T> { 
     List<Node<T>> relatives = new ArrayList<Node<T>>(); 
     T value; 
    } 
} 

Ở đây, nút đầu của một cây có cùng một số T là chính cây và mỗi nút tương đối có cùng một nút T làm nút cha, vì vậy tất cả các nút trong cây sẽ có cùng loại giá trị như phần tử cây f.

Tôi đã sử dụng ArrayList tại đây vì mảng không thể có loại chung.

+0

Điều này thay đổi ngữ nghĩa của chương trình vì Nút không thể truy cập thành viên Tree nữa (trong bài toán gốc có thể). Nhưng nó là một lựa chọn hợp lệ. –

+0

Nút luôn có thể có một trường Tree rõ ràng nếu nó thực sự cần phải tham khảo lại chủ sở hữu của nó, nhưng tôi đoán là Dave không thực sự sử dụng nó như một lớp bên trong. –

+0

Tôi đồng ý với bạn, lớp bên trong có lẽ không cần thiết. –

3

Đối với các lỗi biên dịch để tạo mảng chung khi bạn loại bỏ các T từ lớp bên trong:

Bởi vì đó là một lớp bên trong không tĩnh, đó là trong phạm vi của tham số kiểu lớp ngoài của. Điều này có nghĩa là nó cũng được tham số hóa bởi tham số kiểu của lớp bên ngoài của nó là

vì vậy khi bạn viết TSTNode về cơ bản có nghĩa là TernarySearchTree<T>.TSTNode (chữ T ở đây là chữ T bên ngoài). Vì vậy, TSTNode vẫn là một loại chung chung (mặc dù bạn không thấy bất kỳ dấu ngoặc nào một cách rõ ràng) và việc tạo một mảng thuộc loại chung không thành công.

Bạn có thể tham khảo loại nguyên của TSTNode bằng cách thủ công đủ điều kiện tên: TernarySearchTree.TSTNode.

Vì vậy, new TernarySearchTree.TSTNode[4] là câu trả lời.

Bạn sẽ nhận được một cảnh báo không được kiểm soát, mà bạn có thể bỏ qua (nó là một cái gì đó bạn phải sống với với mảng các kiểu generic)

T.B. loại bỏ các tham số kiểu từ lớp bên trong là gần như chắc chắn là sự lựa chọn đúng, như các lớp bên trong không tĩnh trong Java ngầm có một tham chiếu đến một thể hiện của lớp bên ngoài. Vì vậy, nó đã được tham số hóa với bên ngoài T. Nếu bạn chỉ đơn giản muốn sử dụng cùng một T, không khai báo một số khác.

0

Biến thể trên Itay Maman's solution.

Đây là một câu trả lời cho một câu hỏirộng hơn so với OP được hỏi: Làm thế nào để tạo ra một loạt các thuốc generic được sử dụng chỉ trong nội bộ trong Java? (Giải pháp này KHÔNG được dùng để tạo một mảng chung để trả về cho người dùng - đó sẽ là unsafe as is well recognized.)

Chỉnh sửa: Phiên bản 5: Sử dụng enums có mảng. (Tôi nghĩ rằng V4 là tốt hơn cho OP, nhưng nếu bạn cần một mảng với generics, đây là cách - Josiah Yoder)

public class TernarySearchTreeWithArray<T> { 

    protected static enum Index { 
     PARENT, LOKID, EQKID, HIKID, ARRAY_SIZE; 
    } 

    protected class TSTNode<U> { 
     protected char splitchar; 

     @SuppressWarnings("unchecked") 
     protected TSTNode<U>[] relatives = (TSTNode<U>[]) new TSTNode[Index.ARRAY_SIZE.ordinal()]; 

     private U data; 

     protected TSTNode(char splitchar, TSTNode<U> parent) { 
      this.splitchar = splitchar; 
      relatives[Index.PARENT.ordinal()] = parent; 
     } 
    } 

    private TSTNode<T> root; // When you use it, pass T as U 

    public TernarySearchTreeWithArray() { 
     root = new TSTNode<>(',', null); // When you use it, pass T as U 
    } 
} 
Các vấn đề liên quan