Thinking in Java——筆記(15)

来源:http://www.cnblogs.com/apolloqq/archive/2016/12/19/6196250.html
-Advertisement-
Play Games

Generics ___ The term "generic" means "pertaining or appropriate to large groups of classes." While using someone else’s generic type is fairly easy, ...


Generics


  • The term "generic" means "pertaining or appropriate to large groups of classes."
  • While using someone else’s generic type is fairly easy, when creating your own you will encounter a number of surprises.

Comparison with C++

  • Understanding certain aspects of C++ templates will help you understand the foundations of the concept, as well as the limitations of what you can do with Java generics and why.
  • The ultimate goal is to give you a clear understanding of where the boundaries lie.

Simple generics

  • There are some cases where you want a container to hold multiple types of objects, but typically you only put one type of object into a container.
  • One of the primary motivations for generics is to specify what type of object a container holds, and to have that specification backed up by the compiler.
  • That’s the core idea of Java generics: You tell it what type you want to use, and it takes care of the details.

A tuple library

  • One of the things you often want to do is return multiple objects from a method call.
  • A tuple is simply a group of objects wrapped together into a single object.
  • Each object in the tuple can be of a different type.
  • The longer-length tuples can be created with inheritance.
  • Because of generics, you can easily create any tuple to return any group of types, just by writing the expression.

Generic interfaces

  • The generator knows how to create new objects without any extra information.
  • Typically, a generator just defines one method, the method that produces new objects.
  • Using generics with interfaces is no different than using generics with classes.
  • One of the limitations of Java generics is that you cannot use primitives as type parameters.

Generic methods

  • A generic method allows the method to vary independently of the class.
  • If it’s possible to make a method generic rather than the entire class, it’s probably going to be clearer to do so.
  • With a generic method, you don’t usually have to specify the parameter types, because the compiler can figure that out for you.

Leveraging type argument inference

  • Type argument inference in a generic method can produce some simplification.
  • Type argument inference eliminates the need to repeat the generic parameter list.

Explicit type specification

  • It is possible to explicitly specify the type in a generic method, although the syntax is rarely needed.

Anonymous inner classes

  • Generics can also be used with inner classes and anonymous inner classes.

The mystery of erasure

  • All you find out is the identifiers that are used as the parameter placeholders.
  • There’s no information about generic parameter types available inside generic code.
  • You just can’t know the actual type parameter(s) used to create a particular instance.
  • Any specific type information is erased when you use a generic.
  • Understanding erasure and how you must deal with it will be one of the biggest hurdles you will face when learning Java generics

The C++ approach

  • Writing this kind of code in C++ is straightforward because when a template is instantiated, the template code knows the type of its template parameters.
  • We must assist the generic class by giving it a bound that tells the compiler to only accept types that conform to that bound.
  • A generic type parameter erases to its first bound.
  • The compiler actually replaces the type parameter with its erasure.
  • Generics are only useful when you want to use type parameters that are more "generic" than a specific type.
  • The type parameters and their application in useful generic code will usually be more complex than simple class replacement.

Migration compatibility

  • It is a compromise in the implementation of Java generics, necessary because generics were not made part of the language from the beginning.
  • Erasure reduces the "genericity" of generics.
  • The generic types are present only during static type checking, after which every generic type in the program is erased by replacing it with a non-generic upper bound.
  • The core motivation for erasure is that it allows generified clients to be used with non-generified libraries, and vice versa.
  • Erasure enables this migration towards generics by allowing non-generic code to coexist with generic code.
  • To achieve migration compatibility, each library and application must be independent of all the others regarding whether generics are used.

The problem with erasure

  • Erasure allows existing nongeneric client code to continue to be used without change, until clients are ready to rewrite code for generics.
  • You must constantly be reminding yourself that it only appears that you have type information about a parameter.

The action at the boundaries

  • Using Array.newInstance( ) is the recommended approach for creating arrays in generics.
  • Even though erasure removes the information about the actual type inside a method or class, the compiler can still ensure internal consistency in the way that the type is used within the method or class.
  • What matters at run time is the boundaries: the points where objects enter and leave a method.

Compensating for erasure

  • Sometimes you must compensate for erasure by introducing a type tag. This means you explicitly pass in the Class object for your type so that you can use it in type expressions.
  • The compiler ensures that the type tag matches the generic argument.

Creating instances of types

  • If you use a type tag, you can use newlnstance( ) to create a new object of that type.

Arrays of generics

  • You can’t create arrays of generics. The general solution is to use an ArrayList everywhere that you are tempted to create an array of generics.
  • You can define a reference in a way that makes the compiler happy. This does in fact compile, but it won’t run.
  • The only way to successfully create an array of a generic type is to create a new array of the erased type, and cast that.
  • There’s no way to subvert the type of the underlying array, which can only be Object[].
  • It’s best to not issue any kind of message from the compiler unless the programmer must do something about it.
  • If certain idioms appear in the Java library sources, that’s not necessarily the right way to do it.

Bounds

  • Bounds allow you to place constraints on the parameter types that can be used with generics.
  • This allows you to enforce rules about the types that your generics can be applied to.
  • A potentially more important effect is that you can call methods that are in your bound types.
  • If you are able to constrain that parameter to be a subset of types, then you can call the methods in that subset.
  • It’s important for you to understand that extends has a significantly different meaning in the context of generic bounds than it does ordinarily.

Wildcards

  • It’s clear that the array objects can preserve the rules about the type of objects they contain.
  • Because arrays are completely defined in the language and can thus have both compile-time and runtime checks built in.
  • But with generics, the compiler and runtime system cannot know what you want to do with your types and what the rules should be.

How smart is the compiler?

  • It’s up to the generic class designer to decide which calls are "safe," and to use Object types for their arguments.
  • To disallow a call when the type is used with wildcards, use the type parameter in the argument list.

Contravariance

  • You say that the wildcard is bounded by any base class of a particular class, by specifying <? super MyClass> or even using a type parameter: <? super T>
  • You can thus begin to think of subtype and supertype bounds in terms of how you can "write" (pass into a method) to a generic type, and "read" (return from a method) from a generic type.
  • If you can get away with a static generic method, you don’t necessarily need covariance if you’re just reading.

Unbounded wildcards

  • The unbounded wildcard <?> appears to mean "anything," and so using an unbounded wildcard seems equivalent to using a raw type.
  • <?> can be thought of as a decoration.
  • When you are dealing with multiple generic parameters, it’s sometimes important to allow one parameter to be any type while establishing a particular type for the other parameter.
  • List actually means "a raw List that holds any Object type," whereas List<?> means "a non-raw List of some specific type, but we just don’t know what that type is."
  • So anytime you have a raw type, you give up compile-time checking.
  • The benefit of using exact types instead of wildcard types is that you can do more with the generic parameters.
  • Using wildcards allows you to accept a broader range of parameterized types as arguments.

Capture conversion

  • The unspecified wildcard type is captured and converted to an exact type.
  • Capture conversion only works in situations where, within the method, you need to work with the exact type.

Issues

No primitives as type parameters

  • Autoboxing doesn’t apply to arrays.

Implementing parameterized interfaces

  • A class cannot implement two variants of the same generic interface.

Casting and warnings

  • Using a cast or instanceof with a generic type parameter doesn’t have any effect.

Overloading

  • Overloading the method produces the identical type signature because of erasure.

Self-bounded types

Curiously recurring generics

  • You can’t inherit directly from a generic parameter. However, you can inherit from a class that uses that generic parameter in its own definition.
  • Your class appears, rather curiously, in its own base class.
  • "I’m creating a new class that inherits from a generic type that takes my class name as its parameter."
  • Generics in Java are about arguments and return types, so it can produce a base class that uses the derived type for its arguments and return types.
  • This is the essence of CRG: The base class substitutes the derived class for its parameters.

Self-bounding

  • Self-bounding takes the extra step of forcing the generic to be used as its own bound argument.
  • The type parameter must be the same as the class being defined.
  • The self-bounding idiom is not enforceable.
  • The self-bounding constraint serves only to force the inheritance relationship.
  • If you use self-bounding, you know that the type parameter used by the class will be the same basic type as the class that’s using that parameter.

Argument covariance

  • A derived type method should be able to return a more specific type than the base type method that it’s overriding.
  • Without self-bounding, you overload on argument types. If you use self-bounding, you only end up with one version of a method, which takes the exact argument type.

Dynamic type safety

  • Because you can pass generic containers to pre-Java SE5 code, there’s still the possibility that old-style code can corrupt your containers.
  • A checked container will throw a ClassCastException at the point you try to insert an improper object, as opposed to a pre-generic (raw) container which would inform you that there was a problem when you pulled the object out.
  • It’s fine to put derived-type objects into a checked container that is checking for the base type.

Exceptions

  • A catch clause cannot catch an exception of a generic type, because the exact type of the exception must be known at both compile time and run time.
  • A generic class can’t directly or indirectly inherit from Throwable.
  • Type parameters may be used in the throws clause of a method declaration.

Mixins

  • The fundamental concept is that of mixing in capabilities from multiple classes in order to produce a resulting class that represents all the types of the mixins.
  • One value of mixins is that they consistently apply characteristics and behaviors across multiple classes.
  • Mixins have part of the flavor of aspect-oriented programming (AOP), and aspects are often suggested to solve the mixin problem.

Mixins in C++

  • A more interesting and elegant approach to mixins is using parameterized types, whereby a mixin is a class that inherits from its type parameter.
  • You can think of a mixin as a function that maps existing classes to new subclasses.
  • Java generics don’t permit this. Erasure forgets the base-class type, so a generic class cannot inherit directly from a generic parameter.

Mixing with interfaces

  • A commonly suggested solution is to use interfaces to produce the effect of mixins.

Using the Decorator pattern

  • Decorators are often used when, in order to satisfy every possible combination, simple subclassing produces so many classes that it becomes impractical.
  • Decorator specifies that all objects that wrap around your initial object have the same basic interface.
  • Decorators are implemented using composition and formal structures, whereas mixins are inheritance-based.
  • You could think of parameterized-type-based mixins as a generic decorator mechanism that does not require the inheritance structure of the Decorator design pattern.
  • A significant drawback to Decorator is that it only effectively works with one layer of decoration (the final one), and the mixin approach is arguably more natural.

Mixins with dynamic proxies

  • With a dynamic proxy, the dynamic type of the resulting class is the combined types that have been mixed in.

Latent typing

  • Code that doesn’t care what type it works with can indeed be applied everywhere, and is thus quite "generic."
  • A language with latent typing loosens the constraint (and produces more generic code) by only requiring that a subset of methods be implemented, not a particular class or interface.
  • By not requiring a specific type, your code can be more generic.
  • Latent typing is a code organization and reuse mechanism. With it you can write a piece of code that can be reused more easily than without it.
  • Latent typing does not require either static or dynamic type checking.
  • It initially seems that Java’s generic mechanism is "less generic" than a language that supports latent typing.

Using function objects as strategies

  • Strategy design pattern, which produces more elegant code because it completely isolates "the thing that changes" inside of a function object.
  • A function object is an object that in some way behaves like a function.
  • They can be passed around, and they can also have state that persists across calls.
  • We are creating function objects which perform adaptation, and they are being passed into methods to be used as strategies.

Summary: Is casting really so bad?

  • Without the Java SE5 generic version of the container, you put Objects in and you get Objects out.
  • Type-safe containers come as a side effect of the ability to create more general purpose code.
  • It is fairly easy to write truly generic "holder" classes (which the Java containers are), but to write generic code that manipulates its generic types requires extra effort, on the part of both the class creator and the class consumer, who must understand the concept and implementation of the Adapter design pattern.
  • Introducing any kind of generic mechanism in a later version of a language, after that language has come into general use, is a very, very messy proposition, and one that cannot be accomplished without pain.
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 再次調整項目架構是因為和群友dezhou的一次聊天,我原來的想法是項目儘量做簡單點別搞太複雜了,僅使用了DbContext的註入,其他的也沒有寫介面耦合度很高。和dezhou聊過之後我仔細考慮了一下,還是解耦吧,本來按照軟體設計模式就應該是高內聚低耦合的,低耦合使項目的模塊獨立於其他模塊,增加了可維... ...
  • 因為MongoDb 跨平臺,可以免費使用,讀寫效率高,集群搭建簡單,可以水平擴展等各種因素。 我決定研究一下Mongodb,在查看了相關文檔後發現它對C#的支持不錯,而且還有現成的C#的驅動, 新版的驅動還支持Linq,因為複雜的查詢可以交給Linq去實現。正因為官方的驅動很強大。 剛開始接觸時發現 ...
  • DataTable數據批量寫入資料庫三種方法比較 標簽: it 分類: C#1) insert迴圈插入;2) sqldataadapter.update(dataset,tablename);3) sqlbulkcopy.WriteToServer(datatable);1、生成測試的datatab ...
  • C#使用Jquery zTree實現樹狀結構顯示_非同步數據載入 ...
  • BookMark 我們在平時的工作流使用中,並不是直接這樣一氣呵成將整個工作流直接走完的,通常一個流程到了某一個節點,該流程節點的操作人,可能並不會馬上去處理該流程,而只有當處理人處理了該流程,流程才會繼續往下走。對於不同流程節點的處理人,他所能處理的是不同的流程節點。 就好像我們看書,我們需要書簽 ...
  • 本文章主要是記錄一下我每天的代碼,日後方便回想,和給那些初學者的一些模板。 今天寫一下圖片上傳,因為我主要學習的是MVC那就以MVC為後臺編寫吧。 1.首先要準備的東西是 (1)一個比較好用的上傳插件這個插件。 (2)插件包含的js,和css代碼。如需要插件請留言郵箱。 (3)開始編寫代碼。修改提交 ...
  • 在使用winform程式獲取調用cmd命令提示符時,如果是win7以上的操作系統,會需要必須以管理員身份運行才會執行成功,否則無效果或提示錯誤。 比如在通過winform程式執行cmd命令時,某些情況下如果不是以管理員身份運行,則會提示命令無效。 或者通過winform程式執行Windows Ser ...
  • 狀態機工作流 在上一節Workflow筆記1——工作流介紹中,介紹的是流程圖工作流,後來微軟又推出了狀態機工作流,它比流程圖功能更加強大。 新建項目StatueWorkflowConsoleApp 自動添加了一個起始節點和一個狀態節點. 運行結果如下: 註意執行順序。接下來,擴展此工作流。 1、設置 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...