Use interface or type for variable definition in java?

后端 未结 8 1893
挽巷
挽巷 2020-11-29 05:59
ArrayList aList = new ArrayList();

List aList = new ArrayList();

What\'s the difference between these two and which is better to use and why?

相关标签:
8条回答
  • 2020-11-29 06:32

    Both are deprecated since Java 1.5.

    It should be:

    List<String> list = new ArrayList<String>();
    // or whatever data type you are using in your list
    

    Please read Effective Java by Joshua Bloch, especially these two items:

    • 23: Don't use raw types in new code (this is even available online)
    • 52: Refer to objects by their interfaces

    BTW, if you use Guava, you have a factory method for constructing an ArrayList so you don't have to repeat the type parameter:

    List<String> list = Lists.newArraylist();
    
    0 讨论(0)
  • 2020-11-29 06:36

    This is a Java quirk, due to limited type inference and doctrine OOP. For local variables it's mostly style; if you need some specific feature of the subtype, use the subtype (examples below), but otherwise fine to use either.

    Java style is to use the supertype, to enforce interfaces even within the body of implementations, and for consistency with visible types (Effective Java 2nd Edition: Item 52: Refer to objects by their interfaces). In languages with more type inference, such as C++/C#/Go/etc., you don't need to explicitly state the type, and the local variable will have the specific type.

    For visible types (public or protected: fields, or parameters and return value of methods), you almost always want to use the most general type: interface or abstract class, to provide better flexibility (Effective Java: Item 40: Design method signatures carefully). However, for types that are not visible (private or package-private members, or local variables), it's ok to use either (it's just style) and sometimes necessary to use more specific types, including concrete classes.

    See Effective Java for standard guidelines; personal thoughts follow.

    The reason to use more general types even if not visible is to reduce noise: you're stating that you only need the more general type. Using general types on members that are not visible (like private methods) also reduces churn if you ever change types. However, this doesn't apply to local variables, where it's just changing one line anyway: ConcreteFoo foo = new ConcreteFoo(); to OtherConcreteFoo foo = new OtherConcreteFoo();.

    Cases where you do need the subtype include:

    • You need members only present on the subtype, e.g.:
      • some feature of the implementation, like ensureCapacity for ArrayList<T>
      • (common in test code) some member of a fake class, like (hypothetically) FakeFileSystem#createFakeFile.
    • You rely on the behavior of the subtype, notably in overrides of the supertype's methods, like:
      • having a more general type of parameter,
      • more specific return type, or
      • throwing a more specific or fewer exception types.

    As an example of the last, see Should I close a StringReader?: StringReader.html#close overrides Reader.html#close and does not throw an IOException, so using StringReader instead of Reader for the local variable means you don't need to handle an exception that can't actually occur, and significantly reduces boilerplate.

    0 讨论(0)
  • 2020-11-29 06:40

    I prefer the second in most cases because it signifies that you're not using anything specific in the ArrayList api, and if you need to later you can substitute any other type of List without having to change any code except the first line.

    0 讨论(0)
  • 2020-11-29 06:45

    I know of at least one case when declaring a variable with an interface does not work. When you want to use reflection.

    I made a bug fix on some code where I declared a variable as Map<String, MyObject> and assigned it an instance of HashMap<String, MyObject>. This variable was used as a parameter in a method call that was accessed via reflection. The problem is that reflection tried to find a method with HashMap signature and not the declared Map signature. Since there was no method with a HashMap as a parameter I was unable to find a method by reflection.

    Map<String, Object> map = new HashMap<String, Object>();
    
    public void test(Map<String, Object> m) {...};
    
    Method m = this.getClass().getMethod("test", new Class<?>[]{map.getClass()});
    

    Will not find the method that uses the interface. If you make another version of test that uses HashMap instead then it will work - but now you are forced to declare your variable with a concrete class and not the more flexible interface...

    0 讨论(0)
  • 2020-11-29 06:47

    List is an Interface, whereas ArrayList is an implementation of that interface.

    The second is better because it means you can change your ArrayList for another implementation of List later without needing to change the rest of your application. You may want to do this for performance reasons, or because of other aspects of the behaviour of the List implementation that you have chosen/will choose.

    0 讨论(0)
  • 2020-11-29 06:53

    If you are using Java 1.4 or earlier, then I would use the second one. It's always better to declare your fields as generically as possible, in case you need to make it into something else later on, like a Vector, etc.

    Since 1.5 I would go with the following

    List<String> x = new ArrayList<String>();
    

    It gives you a little bit of type safety. List 'x' can add a String Object, and that's it. When you get an item from the List 'x', you can count on the fact that a String is going to come back. This also helps by removing unnecessary casting, which can make code hard to read when you go back 6 months later and try to remember what your code does. Your compiler/IDE will help you to remember what type should be going in to List 'x' by displaying an error if you try to add any other Object type.

    If you want to add multiple Object types to a List then you could add an Annotation to suppress the compile error

    @SuppressWarnings("unchecked")
    List y = new ArrayList();
    
    0 讨论(0)
提交回复
热议问题