我以为我提供这个垒球的任何人想到了公园。什么是仿制药,有什么优势的仿制药,为什么,在这里,我应该如何使用它们?请保持相当基本的。谢谢。

有帮助吗?

解决方案

  • 让你写的代码使用图书馆的方法的类型安全,即一个列表<string> 保证是一串名单。
  • 作为结果的仿制药被使用的编译可执行的编写时检查在代码类型的安全,即你试图把一个int到那串名单?使用。就因为那是一个小透明运行时的错误。
  • 快于使用的对象,因为它既避免了拳击/拆箱(。净额已经转换 值类型的参考类型或反之亦然)或铸造的对象的需要的参考类型。
  • 让你写代码,适用于多种类型相同的基础行为,即字典<string, int=""> 采用相同的底层代码字典<DateTime, double="">;使用仿制药,框架小组仅已经写入一段代码,以实现两者的结果与上述优势。

其他提示

我真的不想重复自己。我讨厌打字同样的事情往往多于我。我不喜欢重申的事情多次轻微的差异。

而不是创建:

class MyObjectList  {
   MyObject get(int index) {...}
}
class MyOtherObjectList  {
   MyOtherObject get(int index) {...}
}
class AnotherObjectList  {
   AnotherObject get(int index) {...}
}

我可以建立一个可重复使用课...(在这种情况下,你不想使用的原始收集由于某种原因)

class MyList<T> {
   T get(int index) { ... }
}

我现在3x更有效率和我只有保持一个副本。为什么你不会想要维持较少的代码?

这也适用于非集课程,例如一个 Callable<T>Reference<T> 有与其他类。你真的希望延伸 Callable<T>Future<T> 和其他每个相关类创建类安全的版本吗?

我不知道。

不需要定型是一个最大优点Java泛型, ,因为它将执行类型检查在编译时间。这将减少可能的 ClassCastExceptions它可能在运行时,可以导致更强大的代码。

但我怀疑你完全意识到这一点。

每次我看到仿制药,它给 我头痛。我找到最好的部分 Java是它的简单性和最小的 语法和仿制药都不简单 增加大量新的 语法。

在第一次,我没有看到有益的仿制药。我开始学习Java从1.4法(即使Java5是在时间),当我遇到仿制药,我觉得这是更多的代码编写的,我真的不明白的好处。

现代化的IDEs编写代码泛型更容易。

最现代化的、体面的IDEs有足够的智慧,以协助编写代码泛型,特别是与编码完成。

这里是一个例子,做一个 Map<String, Integer>HashMap.代码,我就要类型是:

Map<String, Integer> m = new HashMap<String, Integer>();

事实上,这是一个很大型只是为了让一个新的 HashMap.然而,在现实中,我只需要类型,这么多之前的蚀知道我需要什么:

Map<String, Integer> m = new Ha Ctrl+空间

真的,我需要选择 HashMap 从一个名单的候选人,但基本上IDE知道什么添加,其中包括通用类型。使用正确的工具,使用仿制药是不是太坏的。

此外,由于本类型是已知的,检索时元素从一般的收集、IDE会采取行动,如果对象是已经有一个目的地声明的类型--没有必要铸造IDE知道什么对象的类型。

一个关键优势的仿制药来自的方式,它起着以及与新的Java5的功能。 这里有一个例子的折腾了整数到一 Set 和计算其总:

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);

int total = 0;
for (int i : set) {
  total += i;
}

在这段代码,有三个新的Java5功能:

首先,型和自动装箱的元允许如下:

set.add(10);
set.add(42);

在整数 10 是autoboxed成 Integer 与的价值 10.(和同样的对 42).然后, Integer 被扔到 Set 这是众所周知的举行 Integers.试图把在一个 String 会造成一个编译错误。

接下来,对于为每一个循环需要所有三的那些:

for (int i : set) {
  total += i;
}

第一, Set 含有 Integers用于为每个循环。每个元素都是宣布一个 int 这是允许的 Integer 是装箱回到原始的 int.而事实上,这种拆箱发生众所周知,因为仿制药物用于指定有 Integers举行的 Set.

仿制药可胶带来了一起新的功能,介绍了在Java5,它只是使编码的简单和更安全。大部分时间IDEs有足够的智慧帮助你有很好的建议,因此一般来说,它不会一个整体的更多打字。

坦率地说,因为从中可以看出 Set 例如,我觉得,利用Java5功能,可以使代码更加简明和稳健。

编辑的一个例子没有仿制药

以下是一个说上 Set 例不使用仿制药。这是可能的,但不是愉快的:

Set set = new HashSet();
set.add(10);
set.add(42);

int total = 0;
for (Object o : set) {
  total += (Integer)o;
}

(注:上述代码将产生未转换警告在编译时间。)

当使用非泛型集、类型,进入了收集为对象的类型 Object.因此,在此示例中, Object 是的是什么 added到设置。

set.add(10);
set.add(42);

在上述线路、自动装箱是在玩-原始的 int1042 正在autoboxed入 Integer 对象,这是正在加入的 Set.然而,牢记, Integer 对象是正在处理作为 Objects由于没有类型的信息,以帮助编译器知道什么类型的 Set 应该期望。

for (Object o : set) {

这是一部分,这是至关重要的。因为每次循环的工作是因为 Set 实现了 Iterable 接口,返回一个 Iterator 与类型的信息,如果存在的话。(Iterator<T>, 那是.)

然而,由于没有类型的信息, Set 将返回 Iterator 这将返回值 Set 作为 Objects,这就是为什么元被检索的在于每个循环 必须 的类型 Object.

现在 Object 是从 Set, 它需要被转换到一个 Integer 手动执行的,此外:

  total += (Integer)o;

在这里,一种类型转换的执行从一个 Object 来一个 Integer.在这种情况下,我们知道,这将始终是工作,但手册转换总是让我觉得它是脆弱的代码可以被破坏,如果一个细微的改变是由其他地方。(我觉得每一个类型转换的是一个 ClassCastException 等待发生,但我跑题了...)

Integer 现在是装箱进入一个 int 和允许执行的加入 int 变量 total.

我希望我能说明这一新特点的Java5可以使用与非通用代码,但它不仅仅是作为干净的和直接的作为编写代码,与泛型。而且,在我看来,为了充分利用新的特点在Java5,一个应该看到仿制药,如果在非常少,可汇编时的检查,以防止无效的类型转化扔例外在运行时间。

如果你要搜索Java错误数据库之前1.5被释放,你会找到七倍的错误 NullPointerExceptionClassCastException.因此,它不似乎这是一个伟大的功能,以发现错误,或至少缺陷,坚持后一点烟雾测试。

对我的巨大优势的仿制药,它们的文件 在代码 重要的类型的信息。如果我没想要的那种类型的信息记录中的代码,然后我会用一个动态的语言,或者至少一种语言有更多隐含的类型推理。

保留对象的收藏品,以本身不是一个坏的风格(但后来的共同风格是有效地忽略封).它不取决于你在做什么。通过集合到"算法"是稍微容易检查(在前或compile-time)与泛型。

仿制药在促进Java 参多.通过装置的类型参数,可以通过论点类型。就像样的方法 String foo(String s) 模型的一些行为,不仅对一个特定的串的,但是对于任何字符串 s, ,这样一个喜欢的类型 List<T> 模型的一些行为,不仅对于一种具体类型,但是 对于任何类型. List<T> 说的 对于任何类型 T, 有一种类型的 List 其元素 Ts.所以 List 是的实际上 种类的构造.它需要一种类型为一个参数和结构的另一个类型作为一个结果。

这里有几个例子的一般类型我每天使用。第一,一个非常有用的通用的界面:

public interface F<A, B> {
  public B f(A a);
}

这个接口说 对于一些两种类型, AB, 有个功能(称为 f),需要一个 A 和返回 B. 当你执行这个接口, AB 可以是任何类型你想要的,只要提供的功能 f 这需要前和返回后者。这里有一个例子实施的界面:

F<Integer, String> intToString = new F<Integer, String>() {
  public String f(int i) {
    return String.valueOf(i);
  }
}

前泛型、多是通过 继承 使用 extends 关键词。与泛型,实际上,我们可以做与子类和使用的参数多态性的,而不是。例如,考虑的参数化(通用)类使用计算的散列代码,用于任何类型。而不是压倒一切的对象。哈希码(),我们会使用通用类是这样的:

public final class Hash<A> {
  private final F<A, Integer> hashFunction;

  public Hash(final F<A, Integer> f) {
    this.hashFunction = f;
  }

  public int hash(A a) {
    return hashFunction.f(a);
  }
}

这是更灵活的使用继承的,因为我们可以留的主题,使用的组成和参多没有锁定脆层次结构。

Java泛型不是完美的。你可以抽象过类型,但是你不能抽象过类型的构造,例如。也就是说,你可以说"对任何类型的T"但你不能说"对任何类型的T,需要一种类型的参数"。

我写了一篇关于这些限制的Java泛型,在这里。

一个巨大的胜利用仿制药,它们让你避免子类化。子类化往往会导致脆类层次结构尴尬的扩展和类难以理解单独没有在整个层次结构。

Wereas之前,泛型的你可能会有类似的 Widget 延长 FooWidget, BarWidget, , BazWidget, 与泛型的你可以有一个单一的通用类 Widget<A> 这需要一个 Foo, BarBaz 在其构造给你 Widget<Foo>, Widget<Bar>, , Widget<Baz>.

泛型的避免的性能打拳击和拆箱.基本上,看。vs名单<T>.都做同样的核心事,但名单<T> 将会快得多,因为你不必框向/从对象。

我只是喜欢他们,因为他们给你一个快速的方式来定义自定义的类型(如我使用它们无论如何)。

因此,例如替代定义的结构组成的一串及整数,然后具有实施一整套的对象和方法上如何获得一系列的那些结构等等,你可以只让一词典

Dictionary<int, string> dictionary = new Dictionary<int, string>();

和编译/IDE其他繁重的工作。一个典特别是可以使用的第一类作为一个关键的(没有重复的值)。

最佳利益泛型的代码重复使用。可以说,你有很多的业务对象,你会写的很类似码的每个实体执行的同样的行动。(I.E皇宫SQL操作)。

与泛型,您可以创建一个类将能够给予任何继承的类型自给基类或实现一个指定的接口,像这样:

public interface IEntity
{

}

public class Employee : IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

public class Company : IEntity
{
    public string Name { get; set; }
    public string TaxID { get; set }
}

public class DataService<ENTITY, DATACONTEXT>
    where ENTITY : class, IEntity, new()
    where DATACONTEXT : DataContext, new()
{

    public void Create(List<ENTITY> entities)
    {
        using (DATACONTEXT db = new DATACONTEXT())
        {
            Table<ENTITY> table = db.GetTable<ENTITY>();

            foreach (ENTITY entity in entities)
                table.InsertOnSubmit (entity);

            db.SubmitChanges();
        }
    }
}

public class MyTest
{
    public void DoSomething()
    {
        var dataService = new DataService<Employee, MyDataContext>();
        dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
        var otherDataService = new DataService<Company, MyDataContext>();
            otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });

    }
}

注意重复使用相同的服务给予不同类型或重写现有的方法上。真优雅!

还有许多其他伟大理由使用泛型的对你的工作,这是我最喜欢的。

  • 类型集合-即使你不要使用他们的你很可能会有对付他们从其他图书馆,其他来源。

  • 一般输入流的创建:

    公共class Foo < T>{ 公共T get()...

  • 避免铸-我一直都不喜欢的东西喜欢

    新的比较{ 公共int compareTo(对象o){ 如果(o实例classIcareAbout)...

你基本上用于检查的一个条件,应该仅存在,因为该接口表示的对象。

我的初步反应仿制药物类似于你的-"太乱了,太复杂"。我的经验是,在使用他们一点你得用于他们和代码没有他们感觉不太明确规定,只是不舒服。除此之外,其余的java世界使用他们,所以你们要必须得到与程序最终,对吗?

得到一个很好的例子。想象一下,你有一类称为Foo

public class Foo
{
   public string Bar() { return "Bar"; }
}

例1 现在你要有一个收集Foo的对象。你有两个选择,名单或对列表,两者的工作在一个类似的方式。

Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();

//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());

在上述代码,如果我尝试增加一个类的救火车,而不是Foo,对列表将加入它,但一般的名单Foo将导致一个例外被抛出。

例如两个。

现在你有两个阵列表和你想要呼叫Bar()功能上的每一个。由于兴田。是充满了对象,你有投他们之前,你可以打电话吧。但是,由于通用清单的Foo可以只包含Foos,你可以call Bar()直接在那些。

foreach(object o in al)
{
    Foo f = (Foo)o;
    f.Bar();
}

foreach(Foo f in fl)
{
   f.Bar();
}

你有没有写入一种(或一类)里的关键概念的方法/类不紧密结合到一个特定的数据类型的参数/实例变量(认为链接清单、最大/最小的功能,二进制的搜索,等等)。

你有没有希望你可以重复使用的algorthm/代码,而不诉诸切-n-浆再利用或损害的强型(例如我想要一个 List 串,不是一个 List 事情我 希望 是串!)?

这就是为什么你应该 使用泛型(或者更好的东西).

不要忘记,仿制药不是仅使用的类别,它们也可以使用的方法。例如,采取下列段:

private <T extends Throwable> T logAndReturn(T t) {
    logThrowable(t); // some logging method that takes a Throwable
    return t;
}

它是简单的,但可用于非常优雅。这种做法的好处是,该方法返回不管是什么这是给出。这帮助了当你处理例外情况,需要重新引回来电:

    ...
} catch (MyException e) {
    throw logAndReturn(e);
}

你不会丢失的类型,通过一个方法。你可以扔掉的正确类型的例外,而不仅仅是一个 Throwable, 这将是所有你能做的没有仿制药。

这只是一个简单的例子之一使用通用方法。有相当多的其他整洁的东西,你可以用一般方法。最酷的,在我看来,是型推断有仿制药。采取以下实例(从Josh Bloch的有效Java第2版):

...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
    return new HashMap<K, V>();
}

这不做了很多,但它并减少一些凌乱当的通用类型的长(或嵌套;即 Map<String, List<String>>).

主要的优点,作为米切尔指出的那样,是强大的打字,而不需要定义多种类。

这样你可以做这样的东西:

List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();

没有仿制药,你必须投等等[0]以正确类型的访问其职能。

jvm蒙上无论如何...它隐含地创建了代码的对待的一般类型的"对象",并创建了投到希望的实例。Java泛型只是语法糖。

我知道这是一个C#问题,但是 泛型 是用来在其他语言也和他们使用的/目标是相当类似的。

Java集合的使用 泛型 由于Java1.5.因此,良好的地方使用它们,当你们创造自己的收集对象。

一个例子,我看到几乎到处都是对类,它拥有两个对象,但是需要处理的那些对象在一个通用的方式。

class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F f, S s)
    { 
        first = f;
        second = s;   
    }
}  

只要你使用这两类可以指定这样的对象你想要它来处理任何类型转换的问题将显示在编制时间,而不是运行时间。

仿制药可能也有自己的边界定义的关键词"超级"和'延伸'.例如,如果你要处理一般的类型但是你想要的,以确保它延伸一类称为Foo(其中有一个setTitle方法):

public class FooManager <F extends Foo>{
    public void setTitle(F foo, String title) {
        foo.setTitle(title);
    }
}

虽然不是很有趣就其本身而言,它是有用的,要知道,每当你处理一FooManager,你知道,它将处理MyClass类型,并MyClass延伸Foo。

从太阳Java文件,在回答"为什么我应该使用仿制药?":

"仿制提供了一种方法,用来进行通信的类型集合,以编译器,以便使它可以进行检查。一旦编译器知道的元素类型的收集、编译器可以检查是否有用的集合一贯的和可以插入正确的转换上的价值观正在采取的集合...代码泛使用的是更加清楚和更加安全。... 编译器可以验证,在编制时间,该类限制不违反在运行时间 [着重部分由作者标明地雷].因为程序编制,而不警告,我们可以肯定地说,它不会扔ClassCastException在运行时间。净效应的使用仿制药,特别是在大的方案, 改进的可读性和稳定性.[着重部分由作者标明地雷]"

仿制药能让你创建的对象是强类型,但你没有定义的具体类型。我认为最好有用的例子是名单和类似的课程。

使用的通用清单可以有一个列表,列表中列出任何你想要的,你总是可以参考的强打字的,你不需要转换或类似的东西你会有一阵或标准的列表。

仿制药让你使用强打字的对象和数据结构应该能够举行任何对象。它还消除了繁琐和昂贵的类型转化时检索的对象,从一般结构(拳击/拆箱).

一个例子,它使用两者是相联系的名单。有什么好将一个联的列表类是如果它只能使用目Foo?实施了一个链接清单,可以处理任何种类的目的,本链表和节点,在一个假设的节点内类必须通用的,如果你想要列表中,只含有一种类型的对象。

如果你集合包含价值的类型,他们不需要框/拆箱的对象当中插入收集所以你的表现急剧增加。很酷的附加喜欢resharper可以产生更多的代码,就像foreach循环。

另一个优点使用仿制药(特别是与集合/列表)是你得到编纂的时间类型的检查。这是真正有用的当使用通用的名单而不是名单的对象。

一个最原因是它们提供 类型的安全

List<Customer> custCollection = new List<Customer>;

作为反对,

object[] custCollection = new object[] { cust1, cust2 };

作为一个简单的例子。

在摘要、仿制药,可以指定更多的precisily什么你打算这样做(强打字).

这样做有几个好处:

  • 因为编译器知道更多关于你想做什么,它可以让你忽略了很多类型的铸造的,因为它已经知道的类型将是兼容的。

  • 这也让你早反馈有关correctnes您的节目。东西以前就有未能在运行时(例如因为一个对象不能被铸造的所需类型),现在无法在汇编时的和可以修复的错误之前,你的测试部门的文件一cryptical错误的报告。

  • 编译器可以做更多的优化,避免像拳击,等等。

一对夫妇的事情,以增加/扩大(发言。净的观点):

通用类型可用于创建基于角色的课程和接口。这已经说过,在更基本的方面,但我找到你开始设计代码与类实现一类无关的方式-结果在高度可重复使用的代码。

一般的论点的方法可以做同样的事情,但是他们还帮助应用"告诉别问"原则上浇铸,即"给我我想要什么,如果你不能,你告诉我为什么"。

我使用它们例如在GenericDao实施SpringORM和休眠看起来像这样

public abstract class GenericDaoHibernateImpl<T> 
    extends HibernateDaoSupport {

    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> clazz) {
        type = clazz;
    }

    public void update(T object) {
        getHibernateTemplate().update(object);
    }

    @SuppressWarnings("unchecked")
    public Integer count() {
    return ((Integer) getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session) {
                    // Code in Hibernate for getting the count
                }
        }));
    }
  .
  .
  .
}

通过使用我的仿制药实现这Dao力开发人员通过他们只有实体,他们的目的是为通过仅仅是子类的GenericDao

public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
    public UserDaoHibernateImpl() {
        super(User.class);     // This is for giving Hibernate a .class
                               // work with, as generics disappear at runtime
    }

    // Entity specific methods here
}

我的小框架是更强大的(有东西像筛选、延迟装载、搜索).我只是简化在这里给你一个例子

我喜欢史蒂夫和你在一开始所说的 "太混乱和复杂的" 但现在我看到它的优势

显而易见的好处,如"种类安全"和"不铸造"已经提到的,所以也许我可以谈论一些其他的"好处",我希望它帮助。

首先,泛型是一个独立于语言的概念,海事组织,它可能会更有意义,如果你认为关于经常(runtime)多在同一时间。

例如,多态性的,因为我们知道从目为导向的设计有一个运行概念在这里的叫目的是想通了在运行时间为计划的执行和相关方法被称为因此根据运行时的类型。在仿制药,这个想法有点类似但是一切都发生在汇编的时间。这是什么意思,你如何使用的?

(让我们坚持使用通用方法,以保持它的契约),这意味着你仍然可以有同样的方法在单独的类(就像你以前在多晶型类),但这次他们是自动产生的编译器取决于该类型组在编译时间。你parametrise你的方法的类型你得到在编译时间。因此,而不是写作的方法从零开始 对于每一个类型 你已经为你做的运行时间多态性(压倒一切的方法),你让我们编译器做的工作期间的汇编。这有一个明显的优势,因为你不需要来推断所有可能类型可以用在你的系统,这使得它更没有一个可扩展的代码变化。

类工作的很多相同的方式。你parametrise的类型和代码生成的编译器。

一旦你得到的想法"编制的时间"时,可以使用"界"类型和限制可以通过作为一个参数化的类型,通过课程/方法。所以,你可以控制什么要穿过这是一个强大的东西特别你已经一框架正在消耗的其他人。

public interface Foo<T extends MyObject> extends Hoo<T>{
    ...
}

没有人可以设置sth比其他MyObject。

此外,可以"执行"类型的限制对你的方法的参数,这意味着你可以确保你的方法的参数,将取决于相同的类型。

public <T extends MyObject> foo(T t1, T t2){
    ...
}   

希望所有这一切都使得有意义。

我曾经给这个话题.你可以找到我的幻灯片、代码和音频记录在 http://www.adventuresinsoftware.com/generics/.

使用泛型集合,只是简单和清洁。甚至如果你船上它的其他地方,从中获得的集合是一个双赢的我。

List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
    stuff.do();
}

vs

List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
    Stuff stuff = (Stuff)i.next();
    stuff.do();
}

List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
    Stuff stuff = (Stuff)stuffList.get(i);
    stuff.do();
}

这仅仅是值得的边际"成本"型和你不是一般的大师使用这个和获得价值。

泛型也给你的能力创造更多的可重复使用的目/方法,同时还提供种类型的具体支持。你还获得了大量的业绩,在某些情况下。我不知道完整的规格上Java泛型,但在。净我可以指定约束的类型参数,如实现一个接口构造,并推导。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top