1. ジェネリックの概念の導入 (なぜジェネリックが必要なのか)
まず、次の短いコードを見てみましょう:
public class GenericTest { public static void main(String[] args) { List list = new ArrayList(); list.add("qqyumidi"); list.add("corn"); list.add(100); for (int i = 0; i < list.size(); i++) { String name = (String) list.get(i); // 1 System.out.println("name:" + name); } } }
は List 型のコレクションを定義し、最初に 2 つの文字列型の値をそれに追加し、次に Integer 型の値を追加します。リストのデフォルトのタイプはオブジェクトであるため、これは完全に許可されます。後続のループでは、前に整数型の値をリストに追加するのを忘れたり、その他のエンコードの理由により、//1 と同様のエラーが発生しやすくなります。コンパイル段階は正常ですが、実行時に「java.lang.ClassCastException」例外が発生するためです。したがって、このようなエラーはコーディング中に検出することが困難です。
上記のコーディング プロセス中に、次の 2 つの主な問題があることがわかりました:
1. オブジェクトをコレクションに追加すると、そのオブジェクトがコレクションから取り出されるときに、コレクションはオブジェクトの型を記憶しません。再度、オブジェクトのコンパイルされた型は Object 型に変更されますが、その実行時の型は独自の型のままです。
2. そのため、//1のコレクション要素を取り出す際には、特定の対象型への人為的な強制型変換が必要となり、「java.lang.ClassCastException」例外が発生しやすくなります。
それでは、コンパイル中に問題がない限り、実行時に「java.lang.ClassCastException」例外が発生しないように、コレクション内の要素の型をコレクションが記憶できるようにする方法はあるのでしょうか?答えはジェネリック医薬品を使用することです。
2. ジェネリック医薬品とは何ですか?
ジェネリック、つまり「パラメータ化された型」。パラメーターに関して最もよく知られているのは、メソッドを定義するときに仮パラメーターがあり、メソッドが呼び出されるときに実際のパラメーターが渡されることです。では、パラメーター化された型をどのように理解すればよいでしょうか?名前が示すように、型はメソッド内の変数パラメーターと同様に、元の特定の型からパラメーター化されます。このとき、型はパラメーター形式 (型パラメーターと呼ぶこともできます) としても定義されます。 type (type 引数) を使用または呼び出すときに、特定の型が渡されます。
少し複雑に思えますが、まず、上記の例の一般的な書き方を見てみましょう。
public class GenericTest { public static void main(String[] args) { /* List list = new ArrayList(); list.add("qqyumidi"); list.add("corn"); list.add(100); */ List<String> list = new ArrayList<String>(); list.add("qqyumidi"); list.add("corn"); //list.add(100); // 1 提示编译错误 for (int i = 0; i < list.size(); i++) { String name = list.get(i); // 2 System.out.println("name:" + name); } } }
汎用的な書き込み方法を採用した後、//1 に Integer 型のオブジェクトを追加しようとするとコンパイル エラーが発生します。List
上記の一般的な定義と組み合わせると、List
public interface List<E> extends Collection<E> { int size(); boolean isEmpty(); boolean contains(Object o); Iterator<E> iterator(); Object[] toArray(); <T> T[] toArray(T[] a); boolean add(E e); boolean remove(Object o); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean addAll(int index, Collection<? extends E> c); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); void clear(); boolean equals(Object o); int hashCode(); E get(int index); E set(int index, E element); void add(int index, E element); E remove(int index); int indexOf(Object o); int lastIndexOf(Object o); ListIterator<E> listIterator(); ListIterator<E> listIterator(int index); List<E> subList(int fromIndex, int toIndex); }
List インターフェイスで汎用定義を採用した後、
当然ですが、ArrayList は List インターフェースの実装クラスであり、その定義形式は次のとおりです。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public E get(int index) { rangeCheck(index); checkForComodification(); return ArrayList.this.elementData(offset + index); } //...省略掉其他具体的定义过程 }
このことから、//1 に Integer 型オブジェクトを追加するとコンパイルエラーが発生する理由がソースコードの観点から理解できます。 get( at //2 ) は直接 String 型です。
3. カスタマイズされたジェネリック インターフェイス、ジェネリック クラス、ジェネリック メソッド
上記の内容で、ジェネリックの具体的な操作プロセスを誰もが理解できました。また、インターフェイス、クラス、メソッドもジェネリックスを使用して定義し、それに応じて使用できることもわかっています。はい、具体的な用途では、ジェネリック インターフェイス、ジェネリック クラス、ジェネリック メソッドに分けることができます。
カスタマイズされたジェネリック インターフェイス、ジェネリック クラス、およびジェネリック メソッドは、上記の Java ソース コードの List および ArrayList に似ています。以下のように、ジェネリック クラスとジェネリック メソッドの最も単純な定義を見ていきます:
public class GenericTest { public static void main(String[] args) { Box<String> name = new Box<String>("corn"); System.out.println("name:" + name.getData()); } } class Box<T> { private T data; public Box() { } public Box(T data) { this.data = data; } public T getData() { return data; } }
ジェネリック インターフェイス、ジェネリック クラス、ジェネリック メソッドの定義プロセスでは、通常、T、E、K、V などの形式のパラメーターを使用します。外部使用から渡された型引数を受け取るため、ジェネリック パラメーターを表すためによく使用されます。それでは、渡されたさまざまな型の引数に対して、生成される対応するオブジェクト インスタンスの型は同じなのでしょうか?
public class GenericTest { public static void main(String[] args) { Box<String> name = new Box<String>("corn"); Box<Integer> age = new Box<Integer>(712); System.out.println("name class:" + name.getClass()); // com.qqyumidi.Box System.out.println("age class:" + age.getClass()); // com.qqyumidi.Box System.out.println(name.getClass() == age.getClass()); // true } }
このことから、ジェネリッククラスを使用する場合、異なるジェネリック引数が渡されても、実際には異なる型が生成されるわけではなく、メモリ内には元のジェネリッククラスが 1 つだけ存在することがわかりました。最も基本的な型 (この例では Box) もちろん、論理的には複数の異なるジェネリック型として理解できます。
その理由は、Java のジェネリックスの概念の目的は、コンパイル プロセス中にジェネリックの結果が正しくチェックされた後、ジェネリックスの関連情報が消去されることであるためです。つまり、正常にコンパイルされたクラス ファイルには一般的な情報が含まれていません。一般的な情報は実行時フェーズには入りません。
これは 1 つの文に要約できます。ジェネリック型は論理的には複数の異なる型と見なすことができますが、実際にはすべて同じ基本型です。
4. ワイルドカードを入力します
接着上面的结论,我们知道,Box
为了弄清这个问题,我们继续看下下面这个例子:
public class GenericTest { public static void main(String[] args) { Box<Number> name = new Box<Number>(99); Box<Integer> age = new Box<Integer>(712); getData(name); //The method getData(Box<Number>) in the type GenericTest is //not applicable for the arguments (Box<Integer>) getData(age); // 1 } public static void getData(Box<Number> data){ System.out.println("data :" + data.getData()); } }
我们发现,在代码//1处出现了错误提示信息:The method getData(Box
public class GenericTest { public static void main(String[] args) { Box<Integer> a = new Box<Integer>(712); Box<Number> b = a; // 1 Box<Float> f = new Box<Float>(3.14f); b.setData(f); // 2 } public static void getData(Box<Number> data) { System.out.println("data :" + data.getData()); } } class Box<T> { private T data; public Box() { } public Box(T data) { setData(data); } public T getData() { return data; } public void setData(T data) { this.data = data; } }
这个例子中,显然//1和//2处肯定会出现错误提示的。在此我们可以使用反证法来进行说明。
假设Box
好,那我们回过头来继续看“类型通配符”中的第一个例子,我们知道其具体的错误提示的深层次原因了。那么如何解决呢?总部能再定义一个新的函数吧。这和Java中的多态理念显然是违背的,因此,我们需要一个在逻辑上可以用来表示同时是Box
类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参!且Box>在逻辑上是Box
public class GenericTest { public static void main(String[] args) { Box<String> name = new Box<String>("corn"); Box<Integer> age = new Box<Integer>(712); Box<Number> number = new Box<Number>(314); getData(name); getData(age); getData(number); } public static void getData(Box<?> data) { System.out.println("data :" + data.getData()); } }
有时候,我们还可能听到类型通配符上限和类型通配符下限。具体有是怎么样的呢?
在上面的例子中,如果需要定义一个功能类似于getData()的方法,但对类型实参又有进一步的限制:只能是Number类及其子类。此时,需要用到类型通配符上限。
public class GenericTest { public static void main(String[] args) { Box<String> name = new Box<String>("corn"); Box<Integer> age = new Box<Integer>(712); Box<Number> number = new Box<Number>(314); getData(name); getData(age); getData(number); //getUpperNumberData(name); // 1 getUpperNumberData(age); // 2 getUpperNumberData(number); // 3 } public static void getData(Box<?> data) { System.out.println("data :" + data.getData()); } public static void getUpperNumberData(Box<? extends Number> data){ System.out.println("data :" + data.getData()); } }
此时,显然,在代码//1处调用将出现错误提示,而//2 //3处调用正常。
类型通配符上限通过形如Box extends Number>形式定义,相对应的,类型通配符下限为Box super Number>形式,其含义与类型通配符上限正好相反,在此不作过多阐述了。
五.话外篇
本文中的例子主要是为了阐述泛型中的一些思想而简单举出的,并不一定有着实际的可用性。另外,一提到泛型,相信大家用到最多的就是在集合中,其实,在实际的编程过程中,自己可以使用泛型去简化开发,且能很好的保证代码质量。并且还要注意的一点是,Java中没有所谓的泛型数组一说。
对于泛型,最主要的还是需要理解其背后的思想和目的。
更多Java泛型相关文章请关注PHP中文网!

JVMは、JavanativeInterface(JNI)およびJava Standard Libraryを介してオペレーティングシステムのAPIの違いを処理します。1。JNIでは、Javaコードがローカルコードを呼び出し、オペレーティングシステムAPIと直接対話できます。 2. Java Standard Libraryは統一されたAPIを提供します。これは、異なるオペレーティングシステムAPIに内部的にマッピングされ、コードがプラットフォーム間で実行されるようにします。

modularitydoesnotdirectlyectlyectjava'splatformindepensence.java'splatformendepenceismaindainededainededainededaindainedaindained bythejvm、butmodularityinfluencesApplucationStructure andmanagement、間接的なインパクチャプラット形成依存性.1)

bytecodeinjavaisthe intermediaterepresentationthateNablesplatformindepence.1)javacodeis compiledintobytecodestoredin.classfiles.2)thejvminterpretsorcompilesthisbytecodeintomachinecodeatime、

javaachievesplatformedenceTheTheTheJavavirtualMachine(JVM)、これは、javacodeisisisisisissompiledIntobytecode.2)javaCodeisisisisissompiledevedevicetecode.2)

Javagui開発におけるプラットフォームの独立性は課題に直面していますが、Swing、Javafx、統一外観、パフォーマンス最適化、サードパーティライブラリ、クロスプラットフォームテストを使用することで対処できます。 Javaguiの開発は、クロスプラットフォームの一貫性を提供することを目的としたAWTとSwingに依存していますが、実際の効果はオペレーティングシステムごとに異なります。ソリューションには以下が含まれます。1)SwingおよびJavafxをGUIツールキットとして使用します。 2)uimanager.setlookandfeel()を介して外観を統合します。 3)さまざまなプラットフォームに合わせてパフォーマンスを最適化します。 4)ApachepivotやSWTなどのサードパーティライブラリを使用する。 5)一貫性を確保するために、クロスプラットフォームテストを実施します。

javadevelopmentisnotentirelylylypratform-IndopentDuetoseveralfactors.1)jvmvariationsaffectperformanceandbehavioracrossdifferentos.2)nativeLibrariesviajniintroducePlatform-specificissues.3)giaiasystemsdifferbeTioneplateplatifflics.4)

Javaコードは、さまざまなプラットフォームで実行するときにパフォーマンスの違いがあります。 1)JVMの実装と最適化戦略は、OracleJDKやOpenJDKなどとは異なります。 2)メモリ管理やスレッドスケジューリングなどのオペレーティングシステムの特性もパフォーマンスに影響します。 3)適切なJVMを選択し、JVMパラメーターとコード最適化を調整することにより、パフォーマンスを改善できます。

java'splatformindepentedencehaslimitationsincludingporformanceoverhead、versioncompatibulisisues、changleSwithnativeLibraryIntegration、プラットフォーム固有の機能、およびjvminStallation/maintenation。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ドリームウィーバー CS6
ビジュアル Web 開発ツール

WebStorm Mac版
便利なJavaScript開発ツール

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

ホットトピック









