中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

無錫網(wǎng)站的建設(shè)搜索引擎優(yōu)化關(guān)鍵詞選擇的方法有哪些

無錫網(wǎng)站的建設(shè),搜索引擎優(yōu)化關(guān)鍵詞選擇的方法有哪些,博羅網(wǎng)站建設(shè)哪家便宜,手機網(wǎng)站頁面制作目錄 泛型存在的問題 在泛型中使用基本類型 實現(xiàn)參數(shù)化接口 類型轉(zhuǎn)換和警告 無法實現(xiàn)的重載 基類會劫持接口 自限定類型 奇異遞歸類型 自限定 自限定提供的參數(shù)協(xié)變性 本筆記參考自: 《On Java 中文版》 泛型存在的問題 接下來討論的,是在泛型…

目錄

泛型存在的問題

在泛型中使用基本類型

實現(xiàn)參數(shù)化接口

類型轉(zhuǎn)換和警告

無法實現(xiàn)的重載

基類會劫持接口

自限定類型

奇異遞歸類型

自限定

自限定提供的參數(shù)協(xié)變性


本筆記參考自: 《On Java 中文版》


泛型存在的問題

??????? 接下來討論的,是在泛型中經(jīng)常可能遇到的一些問題。

在泛型中使用基本類型

??????? Java的泛型并不支持基本類型,因此我們無法將其用作泛型的類型參數(shù)。一個替代的方法是使用基本類型的包裝類:

【例子:通過包裝類使用泛型】

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;public class ListOfInt {public static void main(String[] args) {List<Integer> li = IntStream.range(38, 48).boxed() // 將基本類型轉(zhuǎn)換成其對應(yīng)的包裝類.collect(Collectors.toList());System.out.println(li);}
}

??????? 程序執(zhí)行的結(jié)果是:

??????? 這足以應(yīng)付大部分的情況。但如果真的需要追求性能,可以使用專門適配基本類型的集合,例如org.apache.commons.collections.primitives。

??????? 或者,可以使用泛型集合來裝載基本類型:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;public class ByteSet {Byte[] possibles = {1, 2, 3, 4, 5, 6, 7, 8, 9};Set<Byte> mySet1 =new HashSet<>(Arrays.asList(possibles));// 不可行的方式:/* Set<Byte> mySet2 =new HashSet<>(Arrays.<Byte>asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); */
}

??????? 在這里,自動裝箱機制為我們解決了轉(zhuǎn)換問題。但它不會總是有效,例如:

【例子:向數(shù)組中填充對象】

import java.util.*;
import java.util.function.*;interface FillArray {static <T> T[] fill(T[] a, Supplier<T> gen) {// 使用get()填充數(shù)組aArrays.setAll(a, n -> gen.get());return a;}static int[] fill(int[] a, IntSupplier gen) {Arrays.setAll(a, n -> gen.getAsInt());return a;}static long[] fill(long[] a, LongSupplier gen) {Arrays.setAll(a, n -> gen.getAsLong());return a;}static double[] fill(double[] a, DoubleSupplier gen) {Arrays.setAll(a, n -> gen.getAsDouble());return a;}
}interface Rand {// SplittableRandom也是用于生成隨機數(shù)的類SplittableRandom r = new SplittableRandom(47);class StringGenerator implements Supplier<String> {int strlen;StringGenerator(int strlen) {this.strlen = strlen;}@Overridepublic String get() {return r.ints(strlen, 'a', 'z' + 1).collect(StringBuilder::new,StringBuilder::appendCodePoint,StringBuilder::append).toString();}}class IntegerGenerator implements IntSupplier {@Overridepublic int getAsInt() {return r.nextInt(10_000);}}
}public class PrimitiveGenericTest {public static void main(String[] args) {String[] strings = FillArray.fill(new String[5], new Rand.StringGenerator(7));System.out.println(Arrays.toString(strings));int[] integers = FillArray.fill(new int[9], new Rand.IntegerGenerator());System.out.println(Arrays.toString(integers));}
}

??????? 程序執(zhí)行的結(jié)果是:

??????? 由于自動裝箱對數(shù)組無效,因此需要我們手動重載FillArray.fill()方法,或者通過一個生成器來包裝輸出結(jié)果。


實現(xiàn)參數(shù)化接口

??????? 一個類無法實現(xiàn)同一個泛型接口的兩種變體:

因為類型擦除,這兩個變體實際上都表示著原生的Payable。換言之,上述代碼中Hourly將同一個接口實現(xiàn)了兩次。


類型轉(zhuǎn)換和警告

??????? 因為類型擦除,我們無法對類型參數(shù)使用類型轉(zhuǎn)換或instanceof。因此,有時會需要在邊界處進行類型轉(zhuǎn)換:

【例子:在泛型邊界處進行類型轉(zhuǎn)換】

import java.util.Arrays;
import java.util.stream.Stream;class FixedSizeStack<T> {private final int size;private Object[] storage;private int index = 0;FixedSizeStack(int size) {this.size = size;storage = new Object[size];}public void push(T item) {if (index < size)storage[index++] = item;}@SuppressWarnings("unchecked")public T pop() {return index == 0 ?null : (T) storage[--index];}@SuppressWarnings("unchecked")Stream<T> stream() {return (Stream<T>) Arrays.stream(storage);}
}public class GenericCast {static String[] letters ="ABCDEFGHIJKLMNOPQRST".split("");public static void main(String[] args) {FixedSizeStack<String> strings =new FixedSizeStack<>(letters.length);Arrays.stream(letters).forEach(strings::push);System.out.println(strings.pop());strings.stream().map(s -> s + " ").forEach(System.out::print);}
}

??????? 程序執(zhí)行的結(jié)果是:

??????? pop()stram()會產(chǎn)生警告,因為編譯器無法知道這種類型轉(zhuǎn)換是否安全。在本例中,類型參數(shù)T會被擦除成Object

??????? 雖然在泛型的邊界處,類型轉(zhuǎn)換會自動發(fā)生。但有時我們?nèi)匀恍枰謩舆M行類型轉(zhuǎn)換,此時編譯器會發(fā)出警告:

【例子:對泛型進行轉(zhuǎn)型】

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;public class NeedCasting {@SuppressWarnings("unchecked")public void f(String[] args) throws Exception {ObjectInputStream in = new ObjectInputStream(new FileInputStream(args[0]));List<Integer> shapes = (List<Integer>) in.readObject();}
}

??? 實際上,readObject()不會知道它正在讀取什么,因此它會返回Object

??????? 現(xiàn)在注釋掉@SuppressWarnings("unchecked"),并且使用參數(shù)-Xlint:unchecked進行編譯:

警告清楚地告訴了我們,readObject()會返回一個未經(jīng)檢查的Object。

??????? Java 5還引入了一個轉(zhuǎn)型方法,通過Class.cast(),可以將對象強制轉(zhuǎn)換成目標(biāo)類型。這個方法也適用于泛型:

【例子:嘗試強制轉(zhuǎn)換泛型】

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;public class ClassCasting {@SuppressWarnings("unchecked")public void f(String[] args) throws Exception {ObjectInputStream in = new ObjectInputStream(new FileInputStream(args[0]));// 無法編譯的代碼:// List<Integer> lw1 =//         List<>.class.cast(in.readObject()); // 使用cast()進行強制類型轉(zhuǎn)換// 會引發(fā)警告:List<Integer> lw2 = List.class.cast(in.readObject());// 無法編譯:// List<Integer> lw3 = List<Integer>.class.cast(in.readObject());// 會引發(fā)警告List<Integer> lw4 = (List<Integer>) List.class.cast(in.readObject());}
}

??????? 然而,如代碼所示。這些做法都會存在著這樣那樣的限制。


無法實現(xiàn)的重載

??????? 由于類型擦除,下面的這種寫法是不被允許的:

【例子:無法實現(xiàn)的重載】

import java.util.List;public class UseList<W, T> {void f(List<T> v) {}void f(List<W> v) {}
}

??????? 因為被擦除的參數(shù)無法作為單獨的參數(shù)列表,所以我們還需要為每一個相似的方法提高不同的方法名。


基類會劫持接口

??????? 假設(shè)我們想要創(chuàng)建一個類,這個類實現(xiàn)了Comparable接口,這樣這個類的不同對象就能進行互相的比較:

【例子:實現(xiàn)了Comparable的父類】

public class ComparablePetimplements Comparable<ComparablePet> {@Overridepublic int compareTo(ComparablePet arg) {return 0;}
}

??????? 一個好的想法是,任何繼承了這個類的子類,其對象之間應(yīng)該也能進行比較(在這個例子中,父類是Pet,子類就是Cat。然而事實并不會如我們所愿:

??????? 遺憾的是,若繼承了父類的泛型接口,編譯器不會再允許我們添加另一個Comparable接口。在這里,我們只能遵循父類的比較方式。

??? 我們還可以在子類中重寫compareTo()的行為,但這種行為是面向ComparablePet的(而不是限定在這個子類中)。

自限定類型

??????? 自限定類型來自于Java早期的泛型使用習(xí)慣:

class SelfBounded<T extends SelfBounded<T>> { // ...

在這里,類型參數(shù)的邊界就是類本身:SelfBounded有一個類型參數(shù)T,而參數(shù)T的邊界卻又是SelfBounded

??? 這種寫法更加強調(diào)extends在泛型參數(shù)中使用時的含義。

奇異遞歸類型

??????? 先看一個自限定類型的簡化版本。盡管無法直接繼承泛型參數(shù),但我們可以繼承一個使用了泛型參數(shù)的類。

【例子:繼承泛型類】

class GenericType<T> {
}public class CuriouslyRecurringGenericextends GenericType<CuriouslyRecurringGeneric> {
}

????????這種方式被稱為奇異遞歸泛型。其中,“奇異遞歸”是指子類奇怪地出現(xiàn)在了其基類中的現(xiàn)象、

??????? 要理解這一點,首先需要明確:Java泛型的重點在于參數(shù)和返回類型,因此可以生成將派生類型作為參數(shù)和返回值的基類。派生類型也可作為字段,不過此時它們會被擦除為Object

【例子:用子類替換基類的參數(shù)】

??????? 首先定義一個簡單的泛型:

public class BasicHolder<T> {T element;void set(T arg) {element = arg;}T get() {return element;}void f() {System.out.println(element.getClass().getSimpleName());}
}

??????? 在這個基類中,所有方法的接收或返回值(若有)都是T。接下來嘗試使用這個類:

class Subtype extends BasicHolder<Subtype> {
}public class CRGWithBasicHolder {public static void main(String[] args) {// Subtype中的所有方法,其接收和返回的都是Subtype:Subtype st1 = new Subtype(),st2 = new Subtype();st1.set(st2);Subtype st3 = st1.get();st1.f();}
}

??????? 程序執(zhí)行的結(jié)果是:

??????? 需要注意的是,Subtype類中,所有方法的接收和返回值都已經(jīng)變成了Subtype。這就是一個奇異遞歸泛型:基類用子類替換了其參數(shù)。在這里,基類用于提供通用的方法模板,而子類使用的方法都會具有一個具體的類型,即子類自身。


自限定

??????? 上述的BasicHolder可以將任何類型作為其泛型參數(shù):

【例子:BasicHolder的廣泛應(yīng)用】

class Other {
}// 將不相關(guān)的Other作為參數(shù)
class BasicOther extends BasicHolder<Other> {
}

?????? 自限定在這種操作的基礎(chǔ)上更進一步,它強制地把泛型作為自身的邊界參數(shù)進行使用:

// 自限定類型:
class SelfBounded<T extends SelfBounded<T>> {T element;SelfBounded<T> set(T arg) {element = arg;return this;}T get() {return element;}
}class A extends SelfBounded<A> {
}// 屬于SelfBounding<>的類型也可以這樣使用:
class B extends SelfBounded<A> {
}class C extends SelfBounded<C> {C setAndGet(C arg) {set(arg);return get();}
}class D {
}
// 但這種做法是不被允許的:
// class E extends SelfBounding<D> {
// }// 這樣的可以(自限定的語法并非強制性的):
class F extends SelfBounded {
}public class SelfBounding {public static void main(String[] args) {A a = new A();a.set(new A());a = a.set(new A()).get();a = a.get();C c = new C();c = c.setAndGet(new C());}
}

??????? 需要注意的是,自限定類型會要求類處于繼承關(guān)系中。因此像E這種并不處于繼承關(guān)系中的類無法使用自限定。

??????? 除此之外,可以看到編譯器并沒有對F這種寫法發(fā)出警告:

class F extends SelfBounded {}

由此可知,編譯器對自限定的語法并不做強制要求,這需要程序員自己注意(或使用工具保證不會使用原生類型)。

??????? 注意:自限定類型只服務(wù)于強制繼承關(guān)系。若使用自限定,這意味著該類使用的類型參數(shù)和使用該參數(shù)的類屬于同一個基類。

??? 對于普通的泛型類而言,像上例中的E這樣的類型是可以作為泛型參數(shù)的。這種泛型類就沒有對繼承關(guān)系的強制性要求。

??????? 除此之外,自限定還可用于泛型方法:

【例子:使用了自限定的泛型方法】

public class SelfBoundingMethods {static <T extends SelfBounded<T>> T f(T arg) {return arg.set(arg).get();}public static void main(String[] args) {A a = f(new A());}
}

這種做法的特點是,方法f()無法應(yīng)用于自限定參數(shù)規(guī)定范圍之外的對象。


自限定提供的參數(shù)協(xié)變性

??????? 自限定類型的價值在于它可以生成協(xié)變參數(shù)類型,即方法參數(shù)的類型會隨著子類而變化。現(xiàn)在先來看一個協(xié)變參數(shù)類型的例子,這種寫法是Java 5引入的:

【例子:Java中的協(xié)變參數(shù)類型】

class Base {
}class Derived extends Base {
}interface OrdinaryGetter {Base get();
}interface DerivedGetter extends OrdinaryGetter {@OverrideDerived get();
}public class CovariantReturnTypes {void test(DerivedGetter d) {Derived d2 = d.get();}
}

??????? 這種做法有著自洽的邏輯:子類方法可以返回比其基類方法更加具體的類型(但這種寫法在Java 5之前是行不通的)。

??????? 而自限定方法則可以直接返回精確的派生類型:

【例子:自限定的返回值】

interface GenericGetter<T extends GenericGetter<T>> {T get();
}interface Getter extends GenericGetter<Getter> {
}public class GenericsAndReturnTypes {void test(Getter g) {Getter result = g.get();// 因為返回的類型是子類,因此可以用基類來承接:GenericGetter gg = g.get();}
}

??? 不過,這種做法只在引入了協(xié)變類型的Java 5之后有效。

??????? 與上述這兩種形式不同,在普通的類中,參數(shù)的類型無法隨子類型而變化。

【例子:普通類的返回值】

class OrdinarySetter {void set(Base base) {System.out.println("OrdinarySetter.set(Base)");}
}class DerivedSetter extends OrdinarySetter {void set(Derived derived) {System.out.println("DerivedSetter.set(Derived)");}
}public class OrdinaryArguments {public static void main(String[] args) {Base base = new Base();Derived derived = new Derived();DerivedSetter ds = new DerivedSetter();ds.set(derived);// 編譯通過,但這里發(fā)生的不是重寫,是重載:ds.set(base);}
}

??????? 程序執(zhí)行的結(jié)果是:

??????? 盡管在main()中,ds.set(derived)ds.set(base)都是合法的,但發(fā)生的并不是重寫,而是重載。從輸出可以看出,在子類DerivedSetter中存在著兩個set()方法,一個參數(shù)是Base,另一個的是Derived。

??? 若對DerivedSetterset()方法使用@Override注釋,就可以看出問題。

??????? 當(dāng)使用自限定類型時,子類中來自基類的方法的參數(shù)會發(fā)生改變,因此會出現(xiàn)下面這種情況:

【例子:子類方法的參數(shù)會被重寫】

interface SelfBoundSetter<T extends SelfBoundSetter<T>> {void set(T arg);
}interface Setter extends SelfBoundSetter<Setter> {// 未進行任何改動,但實際上set()已經(jīng)被重寫
}public class SelfBoundingAndCovariantArguments {void testA(Setter s1, Setter s2, SelfBoundSetter sbs) {s1.set(s2);// 不允許這么做:// s1.set(sbs);}
}

??????? s1.set(sbs)存在問題:

編譯器認(rèn)為基類無法匹配當(dāng)前set()的類型,盡管上述代碼中并沒有在Setter中顯式地重寫set()方法,但set()的參數(shù)確實已經(jīng)被重寫了。

??????? 若不使用自限定,那么普通的繼承機制就會啟動:

【例子:普通的繼承機制】

// 非自限定的類型:
class OtherGenericSetter<T> {void set(T arg) {System.out.println("GenericSetter.set(Base)");}
}class DerivedGS extends OtherGenericSetter<Base> {void set(Derived derived) {System.out.println("DerivedGS.set(Derived)");}
}public class PlainGenericInheritance {public static void main(String[] args) {Base base = new Base();Derived derived = new Derived();DerivedGS dgs = new DerivedGS();dgs.set(derived);// 發(fā)生了重載:dgs.set(base);}
}

??????? 程序執(zhí)行的結(jié)果是:

??????? 顯然,這里發(fā)生的還是重載。若使用的是自限定,最后只會有一個接收確切類型參數(shù)的方法版本。

http://www.risenshineclean.com/news/5884.html

相關(guān)文章:

  • 做網(wǎng)站設(shè)計的都轉(zhuǎn)行干啥了網(wǎng)址如何被快速收錄
  • 做網(wǎng)站找云無限seo搜索優(yōu)化排名
  • 北京的制作網(wǎng)站的公司在哪里seo學(xué)校培訓(xùn)
  • 汽車圖片查詢網(wǎng)站源碼十大網(wǎng)站排行榜
  • 醫(yī)療網(wǎng)站建設(shè)公司哪家好百度站點
  • 電子商務(wù)網(wǎng)站規(guī)劃書范文桂林市天氣預(yù)報
  • 寧波網(wǎng)站設(shè)計企業(yè)網(wǎng)頁制作的步驟
  • 設(shè)計師培訓(xùn) 網(wǎng)站seo資訊
  • 網(wǎng)站建設(shè)是在商標(biāo)哪個類別16888精品貨源入口
  • 做圖片詳情網(wǎng)站如何注冊自己的網(wǎng)站
  • 百度主動提交工具 wordpress關(guān)鍵詞排名手機優(yōu)化軟件
  • 綜合網(wǎng)站推廣百度站長快速收錄
  • 海口網(wǎng)站建設(shè)專家評價網(wǎng)站推廣的方法和途徑
  • wordpress代碼高亮顯示北京seo案例
  • 河南住房和城鄉(xiāng)建設(shè)廳網(wǎng)官方網(wǎng)站全球搜索網(wǎng)站排名
  • 網(wǎng)站建設(shè)目錄結(jié)構(gòu)doc站長工具官網(wǎng)查詢
  • wordpress twenty fourteen主題做的演示網(wǎng)站新網(wǎng)店怎么免費推廣
  • 專門做推廣的網(wǎng)站網(wǎng)絡(luò)營銷平臺的主要功能
  • 網(wǎng)站建設(shè)中心ping站長工具
  • synology做網(wǎng)站廣州發(fā)布緊急通知
  • python做的網(wǎng)站公司seo
  • 自己做網(wǎng)站自己做SEO百度市場應(yīng)用官方app
  • 國內(nèi)做網(wǎng)站建設(shè)知名的公司品牌推廣的步驟和技巧
  • 云南建設(shè)網(wǎng)站sem培訓(xùn)班培訓(xùn)多少錢
  • 上海網(wǎng)站建設(shè)開發(fā)哪家澤成杭州seo網(wǎng)站推廣排名
  • 在什么網(wǎng)站做公務(wù)員題目中國新聞今日頭條
  • 酒泉市建設(shè)局網(wǎng)站招標(biāo)辦店鋪推廣平臺有哪些
  • 屬于網(wǎng)站建設(shè)過程規(guī)劃和準(zhǔn)備階段的是seo外鏈軟件
  • 做網(wǎng)站委托書seo官網(wǎng)
  • 更好的網(wǎng)站制作濟南seo怎么優(yōu)化