目次
1. ジェネリックの概要
2. ジェネリックが必要な理由
2.1. コンパイル時にデータ型を検出する
2.2强制转换是自动的
运行结果:
三、深入泛型
3.1 、有两个类,我们需要打印他们的成员变量
3.2、重构
3.3使用泛型重构
2.2強制変換は自動です
一、泛型简介
二、为什么需要泛型
2.1、编译期对数据类型进行检测
下面解释一下上面的泛型语法:

Javaジェネリックス

Feb 24, 2017 am 09:56 AM
java ジェネリック

1. ジェネリックの概要

ジェネリックは Java SE 1.5 の新機能です。ジェネリックの本質は パラメータ化された型 であり、操作対象のデータ型がパラメータとして指定されることを意味します。
Java SE 1.5 より前では、ジェネリックスが存在しないため、「任意」パラメータは型オブジェクトを参照することによって実現されていました。「任意」の欠点は、明示的な 強制的な型変換 が必要であることでした。パラメータの種類を事前に設定してください。 強制型変換エラーの場合、コンパイラはエラーを表示しない可能性があり、例外はの実行中にのみ発生します。これはセキュリティリスクです。
ジェネリックの利点は、コンパイル時に型安全性がチェックされ、すべてのキャストが自動的かつ暗黙的に行われるため、コードの再利用が向上することです。

2. ジェネリックが必要な理由

2.1. コンパイル時にデータ型を検出する

まず、次のコードのように、文字列が ArrayList に追加され、整数が「誤って」追加された場合を見ていきます。
エラーはありません:

Javaジェネリックス

しかし、実行されると、エラーが報告されます: "java.lang.classCastException"

Javaジェネリックス

ArrayList は Object 配列を維持するため、private transient Object[] elementData; code> <code>private transient Object[] elementData;
, 使用get()返回的是一个Object对象, 需要强制转换,但是中间混杂一个Integer数值, 导致强制转换失败。这个错误就是由于Object的任意化导致的。
如果能在编译阶段就发现数据类型有错, 那么就很方便,泛型就满足了这个要求:我将这个程序修改一下,ArrayList使用泛型:会发现编译阶段就报错了.
Javaジェネリックス

2.2强制转换是自动的

不使用泛型:

package com.chb.fanxing;public class NoGen {    
private Object ob;    
public NoGen(Object ob) {        
this.ob = ob;
    }
    getter setter...    
    private void showType() {
        System.out.println("数据的实际类型是:" + ob.getClass().getName());
    }    public static void main(String[] args) {
        NoGen ngInt = new NoGen(88);
        ngInt.showType();        int i = (int)ngInt.getOb();
        System.out.println("value = " + i);
        System.out.println("---------------");

        NoGen ngStr = new NoGen("88");
        ngStr.showType();
        String str = (String)ngStr.getOb();
        System.out.println("value = " + str);   
    }
}
ログイン後にコピー

使用泛型:

package com.chb.fanxing;public class Gen<T> {    
private T ob;    
public Gen(T ob) {        
this.ob = ob;
    }
    getter setter...    
    private void showType() {
        System.out.println("T的实际类型:"+ob.getClass().getName());
    }    public static void main(String[] args) {        //定义一个Integer版本
        Gen<Integer> genInt = new Gen<Integer>(88);
        genInt.showType();        int i = genInt.getOb();//此处不用强制转换
        System.out.println("value = " + i);
        System.out.println("----------------------");

        Gen<String> genStr = new Gen<String>("88");
        genStr.showType();
        String str = genStr.getOb();
        System.out.println("value = "+str); 
    }
}
ログイン後にコピー

运行结果:

两个例子的运行结果是一致的

数据的实际类型是:java.lang.Integervalue = 88
---------------数据的实际类型是:java.lang.String
value = 88
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

对比两个例子会发现:

  • 使用泛型,强制转换时自动进行的:

int i = genInt.getOb();//此处不用强制转换
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  • 而不使用泛型,必须要进行手动强制转化

int i = (int)ngInt.getOb();
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

三、深入泛型

3.1 、有两个类,我们需要打印他们的成员变量

class StringDemo {    
private String s;    
public StringDemo (String s) {        
this.s = s;
    }
    setter geter....
}
class DoubleDemo{    
private Double d;    
public DoubleDemo(Double d) {        
this.d = d;
    }
    setter getter...
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

3.2、重构

仔细观察两个类功能基本一致,只是数据类型不一样,考虑到重构,因为Object是所有类的基类,所以可以使用Object作为成员变量,这样代码就可以通用了。重构代码如下:

class ObjectDemo{
    private Object ob;    
    public ObjectDemo(Object ob){        
    this.ob = ob;
    }
    setter getter...
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ObjectDemo测试:

public static void ObjectDemoTest(){
        ObjectDemo strOD = new ObjectDemo("123");
        ObjectDemo dOD = new ObjectDemo(new Double(23));
        ObjectDemo od = new ObjectDemo(new Object());
        System.out.println((String)strOD.getOb());
        System.out.println((Double)dOD.getOb());
        System.out.println(od.getOb());
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

运行结果:
Javaジェネリックス

3.3使用泛型重构

发现上面的ObjectDemoTest()、get() を使用すると 強制変換 が必要な Object オブジェクトが返されますが、途中に整数値が混在しているため、強制変換が失敗します。このエラーは、オブジェクトの恣意化が原因で発生します。

コンパイル段階でデータ型エラーが見つかると、非常に便利です。

ジェネリック はこの要件を満たします: このプログラムを変更し、ArrayList にジェネリックを使用します: コンパイル段階でエラーが報告されることがわかります。 . < img title="" alt="Javaジェネリックス" src="https://img.php.cn/upload/article/000/000/194/2cda60e6a495547777426baff5cd039f-2.png"/>

2.2強制変換は自動です

ジェネリックスを使用しない:

class GenDemo<T>{    
private T t;    
public GenDemo(T t) {        
this.t = t;
    } 
    public void setT(T t) {        
    this.t = t;
    }    
    public T getT() {        
    return t;
    }
}
ログイン後にコピー

ジェネリックスを使用する:

public static void GenTest() {
        GenDemo<String> strOD = new GenDemo<String>("123");
        GenDemo<Double> dOD = new GenDemo<Double>(new Double(23));
        GenDemo<Object> od = new GenDemo<Object>(new Object());
        System.out.println(strOD.getT());
        System.out.println(dOD.getT());
        System.out.println(od.getT());
}
ログイン後にコピー
ログイン後にコピー

実行結果: 2 つの例の実行結果は一貫しています

package com.chb.fanxing;public class NoGen {    
private Object ob;    
public NoGen(Object ob) {        
this.ob = ob;
    }
    getter setter...    private void showType() {
        System.out.println("数据的实际类型是:" + ob.getClass().getName());
    }    public static void main(String[] args) {
        NoGen ngInt = new NoGen(88);
        ngInt.showType();        int i = (int)ngInt.getOb();
        System.out.println("value = " + i);
        System.out.println("---------------");

        NoGen ngStr = new NoGen("88");
        ngStr.showType();
        String str = (String)ngStr.getOb();
        System.out.println("value = " + str);   
    }
}
ログイン後にコピー
ログイン後にコピー

2 つの例を比較すると、次のことがわかります:

    < li>

    ジェネリックを使用すると、強制変換が自動的に実行されます:

package com.chb.fanxing;public class Gen<T> {    
private T ob;    
public Gen(T ob) {        
this.ob = ob;
    }
    getter setter...    private void showType() {
        System.out.println("T的实际类型:"+ob.getClass().getName());
    }    public static void main(String[] args) {        //定义一个Integer版本
        Gen<Integer> genInt = new Gen<Integer>(88);
        genInt.showType();        int i = genInt.getOb();//此处不用强制转换
        System.out.println("value = " + i);
        System.out.println("----------------------");

        Gen<String> genStr = new Gen<String>("88");
        genStr.showType();
        String str = genStr.getOb();
        System.out.println("value = "+str); 
    }
}
ログイン後にコピー
ログイン後にコピー

  • ジェネリックを使用しない場合、手動で行う必要があります。変換
数据的实际类型是:java.lang.Integervalue = 88
---------------数据的实际类型是:java.lang.String
value = 88
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

3. 詳細なジェネリック🎜🎜3.1. 2 つのクラスがあり、そのメンバー変数を出力する必要があります🎜
int i = genInt.getOb();//此处不用强制转换
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
🎜3. 2 つの基本的な関数を注意深く観察します。クラスは同じですが、データ型が異なります。リファクタリングを考慮すると、Object はすべてのクラスの基本クラスであるため、Object をメンバー変数として使用して、コードを それは世界共通です 🎜。リファクタリングされたコードは次のとおりです: 🎜
int i = (int)ngInt.getOb();
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
🎜ObjectDemo テスト: 🎜
class StringDemo {    
private String s;    
public StringDemo (String s) {        
this.s = s;
    }
    setter geter....
}
class DoubleDemo{    
private Double d;    
public DoubleDemo(Double d) {        
this.d = d;
    }
    setter getter...
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
🎜実行結果: 🎜Javaジェネリックス🎜🎜3.3 汎用リファクタリングの使用🎜🎜 上記の ObjectDemoTest() では 🎜強制変換🎜 を使用する必要があることがわかりました。面倒です🎜 正しい変換を行うためには、変換するデータ型も事前に知っておく必要があります。そうしないと、ビジネスをコンパイルするときは問題ありませんが、実行すると「classCastException」が発生します。したがって、キャストを自分で行う必要はありません。これはジェネリックにとって特に重要です。 🎜
class ObjectDemo{
    private Object ob;    
    public ObjectDemo(Object ob){        
    this.ob = ob;
    }
    setter getter...
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
🎜 テスト: 🎜 手動キャストを排除します 🎜🎜
public static void ObjectDemoTest(){
        ObjectDemo strOD = new ObjectDemo("123");
        ObjectDemo dOD = new ObjectDemo(new Double(23));
        ObjectDemo od = new ObjectDemo(new Object());
        System.out.println((String)strOD.getOb());
        System.out.println((Double)dOD.getOb());
        System.out.println(od.getOb());
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
🎜 上記の一般的な構文を説明しましょう: 🎜🎜 データの型が実際に渡される、入力の型。データが決定され、T がメソッドのメンバー、パラメーター、および戻り値の型として使用されます。 🎜T は単なる名前です。自由に選択できます。 🎜クラス GenDemo、T には制限はありません。実際には Object と同等であり、🎜 クラス GenDemo と同等です。 🎜 Object と比較して、ジェネリックスを使用して定義されたクラスは、定義および宣言中に を使用して実際のデータ型を指定できます。 🎜🎜GenDemo🎜🎜 dOD = new GenDemo🎜 🎜( new Double(23)); 🎜 を指定しないままにすることもでき、その場合は強制変換が必要です。 🎜🎜以下で Java ジェネリックを続けます 🎜制限付きジェネリック 🎜複数のインターフェイス制限 🎜ワイルドカード ジェネリック 🎜

一、泛型简介

  泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
  在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
  泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

二、为什么需要泛型

2.1、编译期对数据类型进行检测

首先我们看一个案例,向一个ArrayList中添加字符串,“不小心”添加了整数,如下面代码,
并没有错误:

Javaジェネリックス

但是执行时,会报错:“java.lang.classCastException”

Javaジェネリックス

因为ArrayList中维护的是一个Object数组, private transient Object[] elementData;
, 使用get()返回的是一个Object对象, 需要强制转换,但是中间混杂一个Integer数值, 导致强制转换失败。这个错误就是由于Object的任意化导致的。
如果能在编译阶段就发现数据类型有错, 那么就很方便,泛型就满足了这个要求:我将这个程序修改一下,ArrayList使用泛型:会发现编译阶段就报错了.
Javaジェネリックス

2.2强制转换是自动的

不使用泛型:

package com.chb.fanxing;public class NoGen {    
private Object ob;    
public NoGen(Object ob) {        
this.ob = ob;
    }
    getter setter...    private void showType() {
        System.out.println("数据的实际类型是:" + ob.getClass().getName());
    }    public static void main(String[] args) {
        NoGen ngInt = new NoGen(88);
        ngInt.showType();        int i = (int)ngInt.getOb();
        System.out.println("value = " + i);
        System.out.println("---------------");

        NoGen ngStr = new NoGen("88");
        ngStr.showType();
        String str = (String)ngStr.getOb();
        System.out.println("value = " + str);   
    }
}
ログイン後にコピー
ログイン後にコピー

使用泛型:

package com.chb.fanxing;public class Gen<T> {    
private T ob;    
public Gen(T ob) {        
this.ob = ob;
    }
    getter setter...    private void showType() {
        System.out.println("T的实际类型:"+ob.getClass().getName());
    }    public static void main(String[] args) {        //定义一个Integer版本
        Gen<Integer> genInt = new Gen<Integer>(88);
        genInt.showType();        int i = genInt.getOb();//此处不用强制转换
        System.out.println("value = " + i);
        System.out.println("----------------------");

        Gen<String> genStr = new Gen<String>("88");
        genStr.showType();
        String str = genStr.getOb();
        System.out.println("value = "+str); 
    }
}
ログイン後にコピー
ログイン後にコピー

运行结果:

两个例子的运行结果是一致的

数据的实际类型是:java.lang.Integervalue = 88
---------------数据的实际类型是:java.lang.String
value = 88
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

对比两个例子会发现:

  • 使用泛型,强制转换时自动进行的:

int i = genInt.getOb();//此处不用强制转换
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  • 而不使用泛型,必须要进行手动强制转化

int i = (int)ngInt.getOb();
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

三、深入泛型

3.1 、有两个类,我们需要打印他们的成员变量

class StringDemo {    
private String s;    
public StringDemo (String s) {        
this.s = s;
    }
    setter geter....
}
class DoubleDemo{    
private Double d;    
public DoubleDemo(Double d) {        
this.d = d;
    }
    setter getter...
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

3.2、重构

仔细观察两个类功能基本一致,只是数据类型不一样,考虑到重构,因为Object是所有类的基类,所以可以使用Object作为成员变量,这样代码就可以通用了。重构代码如下:

class ObjectDemo{
    private Object ob;    
    public ObjectDemo(Object ob){        
    this.ob = ob;
    }
    setter getter...
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ObjectDemo测试:

public static void ObjectDemoTest(){
        ObjectDemo strOD = new ObjectDemo("123");
        ObjectDemo dOD = new ObjectDemo(new Double(23));
        ObjectDemo od = new ObjectDemo(new Object());
        System.out.println((String)strOD.getOb());
        System.out.println((Double)dOD.getOb());
        System.out.println(od.getOb());
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

运行结果:
Javaジェネリックス

3.3使用泛型重构

发现上面的ObjectDemoTest() 中必须要使用强制转换,这比较麻烦,我们还必须事先知道要转换的数据类型,才能进行正确的转换,否则,会出现错误, 业务编译时没有问题,但是一运行,会出现”classCastException”。所以我们需要不用自己进行强制转换,这是泛型就尤为重要。

class GenDemo<T>{    private T t;    public GenDemo(T t) {        this.t = t;
    } 
    public void setT(T t) {        this.t = t;
    }    public T getT() {        return t;
    }
}
ログイン後にコピー

测试:省去了手动进行强制转换

public static void GenTest() {
        GenDemo<String> strOD = new GenDemo<String>("123");
        GenDemo<Double> dOD = new GenDemo<Double>(new Double(23));
        GenDemo<Object> od = new GenDemo<Object>(new Object());
        System.out.println(strOD.getT());
        System.out.println(dOD.getT());
        System.out.println(od.getT());
}
ログイン後にコピー
ログイン後にコピー

下面解释一下上面的泛型语法:

使用表示一个类型持有者名称, 相当于一个形参,数据的类型是有实际传入的数据的类型决定,然后T作为成员、参数、方法的返回值的类型。
T仅仅是一个名字,可以随意取的。
class GenDemo , T没有进行任何限制, 实际相当于 Object,  
等同于 class GenDemo。
与Object相比,使用泛型所定义的类,在定义和声明,可以使用来制定真实的数据类型,如:

GenDemo dOD = new GenDemo(new Double(23));
也可以不指定,那么就需要进行强制转换。

 以上就是java之泛型的内容,更多相关内容请关注PHP中文网(www.php.cn)!


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのアームストロング数 Javaのアームストロング数 Aug 30, 2024 pm 04:26 PM

Java のアームストロング番号に関するガイド。ここでは、Java でのアームストロング数の概要とコードの一部について説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

See all articles