目次
1. ジェネリックス
1.1 ジェネリックスの使用法
1.1.1 ジェネリックスの概念
1.4.4类型推导
1.2裸类型
1.3擦除机制
1.3.1关于泛型数组
1.3.2泛型的编译与擦除
1.4.1泛型的上界
1.4.2特殊的泛型上界
1.4.3泛型方法
2.通配符
2.1通配符的概念
2.2通配符的上界
2.3通配符的下界
ホームページ Java &#&チュートリアル Java のジェネリックスとワイルドカードの分析例

Java のジェネリックスとワイルドカードの分析例

May 11, 2023 pm 11:40 PM
java

    余談: ジェネリックとワイルドカードは、Java 文法の中で最も難しい構文の 2 つです。ジェネリックとワイルドカードを学習する主な目的は、次のことができるようになることです。ソースコードは理解できましたが、実際にはあまり使用していません。

    Java のジェネリックスとワイルドカードの分析例

    1. ジェネリックス

    1.1 ジェネリックスの使用法

    1.1.1 ジェネリックスの概念

    《 「Java プログラミングの考え方」の言葉: 一般的なクラスとメソッドは、特定の型 (基本型またはカスタム クラス) のみを使用できます。複数の型に適用できるコードを作成する場合、この厳格な制限はコードを非常に制限することになります。 Java5 からはジェネリックの仕組みが導入されましたが、このジェネリックとは何を意味するのでしょうか?一般的なクラスやメソッドでは特定の型しか使用できないため、コードに大きな制約が課せられます(例:3つの数値の最大値を求めるメソッド)。先頭のメソッドのパラメータリストの型が#であるとします。 ##Integer、3 つの整数データから最大値を見つけるのは問題なく、このプログラムは完璧に実行できますが、3 つの浮動小数点数の最大値を見つけたい場合、このプログラムは正常にコンパイルされます。ただし、現時点では場合は、別のオーバーロードされたメソッドを作成し、Double に基づいてパラメーター リストと実装関数を実装することを選択できます。これでも問題を解決できます。しかし、問題について考えたことはありますか?問題がある場合はどうすればよいでしょうか? 1 万または 100 万の型には、3 つのオブジェクトのうち最大のオブジェクトが必要です。100 万個のオーバーロードされたメソッドを作成したらどうすればよいでしょうか?これは不可能です。この種の問題を解決するために、ジェネリックが導入されました。ジェネリックはパラメータ化された型の概念を実装し、コードで複数の型を適用できるようにします。一般に、ジェネリックは「非常に多くの型に適用できる」ことを意味します。ジェネリックスを使用すると、型を「パラメーター」としてクラス、インターフェイス、メソッドに渡すことができるため、クラスとメソッドは最も幅広い表現機能を持つことができ、パラメーターが異なるからといって別の型を作成する必要はありません。

    注: 基本型は型パラメーターとして使用できません。

    1.1.2 ジェネリック クラス
    コードの一部を通じてジェネリックを理解できます。まず、ジェネリックを使用していない次のコードを見てください:

    /**
     * 不使用泛型
     */
    class A {
    }
    class Print {
        private A a;
    
        public Print(A a) {
            setA(a);
            System.out.println(this.a);
        }
        public void setA(A a) {
            this.a = a;
        }
        public A getA() {
            return this.a;
        }
    }
    
    public class Generic {
       public static void main(String[] args) {
            Print print = new Print(new A());
        }
    }
    ログイン後にコピー

    //output:A@1b6d3586

    ジェネリックスを使用せずにクラスを作成することは問題ありませんが、このクラスの再利用性はあまり良くありません。クラス

    A# しか保持できません。 ## オブジェクトは他のクラスのオブジェクトを保持できません。遭遇するすべての型に対して新しいクラスを作成する必要はありません。これは非現実的です。クラスを研究すると、Object クラスがすべてのクラスの親クラスであることがわかります。そのため、Object クラスはすべての型参照を受け入れることができ、Print を作成できます。 クラス保持 Object タイプのオブジェクトがあります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>/** * 使用Object类 */ class B{ } class Print1 { private Object b; public Print1(Object b) { setB(b); System.out.println(this.b); } public void print(Object b) { setB(b); System.out.println(this.b); } public void setB(Object b) { this.b = b; } } public class Generic1 { public static void main(String[] args) { Print1 print1 = new Print1(new B());//打印B类型 int i = 2022; print1.print(i);//打印整型类型 print1.print(&quot;这是一个字符串对象!&quot;);//打印字符串类型 } }</pre><div class="contentsignin">ログイン後にコピー</div></div>

    //output:
    //B@1b6d3586

    //2022
    //これは文字列オブジェクトです。

    Print1

    は任意の型を受信して​​出力できますが、これは私たちが望む結果ではありません。配列を使用するシーケンス テーブル クラスを実装する場合について考えてみましょう。これ、もしこの配列がどんな型でも受け取れるとしたら非常に混乱します、データを取り出すときに、どのような型のデータが取り出されるのかが判断できず、取り出されたデータは Object です。型変換により、クラスが保持するオブジェクトの型を指定でき、コンパイラは型の正確さをチェックできます。ジェネリックスは、この目的を完全に達成します。次に、上記のコードをジェネリック クラスに書き直します。次に、まずジェネリックスの構文を理解する必要があります。ジェネリック クラスを作成するための構文は次のとおりです:

    class class name< ジェネリック パラメータ リスト> {
    権限変更されたジェネリック パラメータ変数名;//ジェネリック メンバー変数

    権限変更された戻り値の型メソッド名 (パラメータ リスト){}//パラメータ リストと戻り値の型は Generic にすることができます
    }

    例:
    class Print2<T> {
        private T c;
    
        public void print(T c) {
            setC(c);
            System.out.println(this.c);
        }
    
        public void setC(T c) {
            this.c = c;
        }
    }
    ログイン後にコピー

    ジェネリック クラスを使用するための構文は次のとおりです:

    ジェネリック クラス<型引数> ; 変数名; // ジェネリック クラス参照を定義します
    new generic class(constructor argument); //ジェネリック クラス オブジェクトをインスタンス化します


    例:
    Print2<Integer> print3 = new Print2<Integer>();
    ログイン後にコピー

    Useクラスを実装して使用するためのジェネリックス:

    /**
     * 使用泛型
     */
    class C{ }
    class Print2<T> {
        private T c;
    
        public void print(T c) {
            setC(c);
            System.out.println(this.c);
        }
    
        public void setC(T c) {
            this.c = c;
        }
    }
    public class Generic2{
        public static void main(String[] args) {
            Print2 print2 = new Print2<>();//打印C类型
            print2.print(new C());
            Print2 print3 = new Print2<>();//打印整型类型
            print3.print(2022);
            Print2 print4 = new Print2<>();//打印字符串类型
            print4.print("这是一个字符串对象!");
        }
    }
    ログイン後にコピー

    /**#** 出力:
    *C@1b6d3586

    * 2022
    * これは文字列オブジェクトです。
    */


    クラス名 後の

    これはプレースホルダーを表し、現在のクラスがジェネリック クラスであることを示します。

    [仕様] 型パラメータは通常大文字で表され、一般的に使用される名前は次のとおりです:

    E は Element を表します

    K は Key を表します

    V は を表しますValue

    N は Number

    T を表し、Type

    S、U、V など - 2 番目、3 番目、4 番目のタイプ

    //一个泛型类
    class ClassName<T1, T2, ..., Tn> { }
    ログイン後にコピー

    を表します。ジェネリック クラスの場合、このクラスのオブジェクトが保持する型を指定すると、オブジェクトはこの型のオブジェクトのみを受け取ることができます。他の型のオブジェクトが渡された場合、コンパイラはエラーを報告し、ジェネリック メソッドの戻り値を受け取ります。値を使用する場合、強制的な型変換 (ダウンキャスト) は必要ありませんが、

    Object

    クラスを使用する場合は強制的な型変換が必要です。

    1.1.3类型推导

    使用泛型类时,可以通过泛型类型中传入的类型来推导实例化该泛型类时所需的类型参数,换个说法,定义泛型对象时,前面的尖括号内必须指定类型,后面实例化时可以不指定。如:

    Print2<Integer> print3 = new Print2<>();//后面尖括号内可省略
    ログイン後にコピー

    1.2裸类型

    裸类型其实很好理解,就是一个泛型类,你不去指定泛型对象持有的类型,这样的一个类型就是裸类型。 比如:

    public static void main(String[] args) {
            Print2 print2 = new Print2();
            print2.print(2022);
            print2.print("字符串");
        }
    ログイン後にコピー

    //output:
    //2022
    //字符串

    我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制。

    1.3擦除机制

    1.3.1关于泛型数组

    介绍泛型的擦除机制之前,我们先来了解泛型数组·,先说结论,在Java中不允许实例化泛型数组,如果一定要建立一个泛型数组,正确的做法只能通过反射来实现,当然有一个“捷径”可以不使用反射来创建泛型数组。创建的代码如下:

    1.通过捷径创建,大部分情况下不会出错。

    public class MyArrayList<T> {
        public T[] elem ;
        private int usedSize;
    
        public MyArrayList(int capacity) {
            this.elem = (T[])new Object[capacity];
        }
    }
    ログイン後にコピー

    2.通过反射创建,现在只给代码,具体为什么要这么做后续介绍反射再说。

    public class MyArrayList<T> {
        public T[] elem ;
        private int usedSize;
        
        public MyArrayList(Class<T> clazz, int capacity) { 
            this.elem = (T[]) Array.newInstance(clazz, capacity); 
        }
    }
    ログイン後にコピー
    1.3.2泛型的编译与擦除

    我们先来实现一个简单的泛型顺序表,不考虑扩容问题,只实现简单的增删操作,来看看构造方法部分编译后的反汇编。

    import java.lang.reflect.Array;
    
    public class MyArrayList<T> {
        public T[] elem ;
        private int usedSize;
    
        public MyArrayList(int capacity) {
            this.elem = (T[])new Object[capacity];
        }
        public MyArrayList(Class<T> clazz, int capacity) {
            this.elem = (T[]) Array.newInstance(clazz, capacity);
        }
    }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    我们发现所有的泛型占位符T都被擦除替换成Object了,这就说明Java的泛型机制是在编译期实现的,而泛型机制实现就是通过像这样的擦除机制实现的,并在编译期间完成类型的检查。

    我们通过打印持有不同类型的MyArrayList类来看看,泛型机制到底是不是不会出现在运行期间,如果是的话,打印出的类型都应该是MyArrayList

    public static void main(String[] args) {
            MyArrayList<Integer> list1 = new MyArrayList<>(10);
            MyArrayList<String> list2 = new MyArrayList<>(10);
    
            System.out.println(list1);
            System.out.println(list2);
        }
    ログイン後にコピー

    /**
    * output:
    * MyArrayList@1b6d3586
    * MyArrayList@4554617c
    */

    我们发现打印的类型是一样的,都是MyArrayList,所以可以得出一个结论,泛型是发生在编译期,泛型的类型检查是在编译期完成的,泛型的实现是通过擦除机制实现的,类后面的占位符都会被擦除,其他的占位符都会被替换成Object。当然,这是在泛型参数没有指定上界的情况下,如果存在上界,那占位符会擦除成上界的类型或接口,其实没有指定上界,上界默认为Object,什么是泛型上界,嘘,等一下再说。

    根据擦除机制,也能解释为什么Java当中不能实例化泛型数组了,因为泛型数组前面的占位符会被擦除成Object,实际上是创建一个Object数组,而Object数组中什么类型都能放,这就导致取数据时不安全,因为你不能确定数组里面存放的元素全部都是你预期的类型,所以为了安全,Java不允许实例化泛型数组。

    1.4泛型的上界

    1.4.1泛型的上界

    在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

    class 泛型类名称<类型形参 extends 类型边界> {
    ...
    }

    例如:NumberInteger,Float,Double等相关数字类型的父类。

    public class MyArrayList<T extends Number> {
    	
    }
    ログイン後にコピー

    那么这个MyArrayList泛型类只能指定持有Number类以及Number的子类,像这样就给泛型的类型传参做了约束,这个约束就是泛型的上界,泛型类被类型边界约束时,只能指定泛型类持有类型边界这个类及其子类。

    MyArrayList<Integer> list1 = new MyArrayList<>(10);//正确
            MyArrayList<Double> list2 = new MyArrayList<>(10);//正确
            MyArrayList<String> list3 = new MyArrayList<>(10);//错误,因为String不是Number的子类
    ログイン後にコピー
    1.4.2特殊的泛型上界

    假设需要设计一个泛型类,能够找出数组中最大的元素。

    class MaxVal<T extends Comparable<T>> {
        public T max(T[] data) {
            T max = data[0];
            for (int i = 0; i < data.length; i++) {
                if (max.compareTo(data[i]) < 0) max = data[i];
            }
            return max;
        }
    }
    ログイン後にコピー
    ログイン後にコピー

    由于引用类型的比较需要使用Comparable接口来判断大小,所以所传入的类需要实现Comparable接口,上面这个泛型的类型参数的上界是一个特殊的上界,表示所传入的类型必须实现Comparable接口,不过实现了Comparable接口的类,那也就是Comparable的子类了,综上,像这样类似需要通过实现某一个接口来达到预期功能的类型,使用泛型时需指定泛型的上界,并且该传入的类型必须实现该上界接口。

    1.4.3泛型方法

    有泛型类,那么就一定有泛型接口,泛型方法,其中泛型接口与泛型类的创建和使用是一样的,所以我们重点介绍泛型方法的创建与使用。 创建泛型方法的基本语法:

    方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }

    例如上面实现求数组中最大元素泛型版的方法如下:

    class MaxVal<T extends Comparable<T>> {
        public <T extends Comparable<T>> T max(T[] data) {
            T max = data[0];
            for (int i = 0; i < data.length; i++) {
                if (max.compareTo(data[i]) < 0) max = data[i];
            }
            return max;
        }
    }
    ログイン後にコピー

    对于非static修饰的静态方法, <类型形参列表>可以省略,上述代码可以变成:

    class MaxVal<T extends Comparable<T>> {
        public T max(T[] data) {
            T max = data[0];
            for (int i = 0; i < data.length; i++) {
                if (max.compareTo(data[i]) < 0) max = data[i];
            }
            return max;
        }
    }
    ログイン後にコピー
    ログイン後にコピー

    但是,如果是一个static修饰的静态方法,<类型形参列表>不可以省略,因为静态方法不依赖与对象,它的使用不用实例化对象,所以必须有单独的类型参数列表来指定持有的对象类型。

    class MaxVal<T extends Comparable<T>> {
        public static <T extends Comparable<T>> T max(T[] data) {
            T max = data[0];
            for (int i = 0; i < data.length; i++) {
                if (max.compareTo(data[i]) < 0) max = data[i];
            }
            return max;
        }
    }
    ログイン後にコピー
    1.4.4类型推导

    和泛型类一样,泛型方法也有类型推导的机制,如果不使用类型推导,那么泛型方法是这么使用的:

    Java のジェネリックスとワイルドカードの分析例

    使用类型推导图中画圆圈部分可以省略。

    Java のジェネリックスとワイルドカードの分析例

    在泛型类中没有如下的父子类关系:

    public class MyArrayList<E> { ... }
     // MyArrayList<Object> 不是 MyArrayList<Number> 的父类型 
     // MyArrayList<Number> 也不是 MyArrayList<Integer> 的父类型
    ログイン後にコピー

    但是使用通配符这两种类是有符子类关系的。

    2.通配符

    2.1通配符的概念

    ?就是一个通配符,用与泛型的使用,与泛型不同的是,泛型T是确定的类型,传入类型实参后,它就确定下来了,而通配符更像是一种规定,规定一个范围,表示你能够传哪些参数。 一个泛型类名尖括号之内仅含有一个?,就会限制这个泛型类传入的类型为Object,相当于没有限制,但是获取元素时由于不能确定具体类型,只能使用Object引用接收,所以<?>也被称为无界通配符。

    //使用泛型打印顺序表
        public static<T> void printList1(ArrayList<T> list) {
            for (T x:list) {
                System.out.println(x);
            }
        }
        //使用通配符打印顺序表
        public static void printList2(ArrayList<?> list) { 
            for (Object x:list) { 
                System.out.println(x); 
            }
        }
    ログイン後にコピー

    使用泛型T能够确定传入的类型就是T类型,所以使用T类型的变量接收,而通配符?没有设置边界的情况下,默认上界是Object没有下界,为了保证安全,只能使用Object类型的变量接收。

    通配符是用来解决泛型无法协变的问题的,协变指的就是如果StudentPerson的子类,那么List<Student>也应该是List<Person>的子类。但是泛型是不支持这样的父子类关系的。

    2.2通配符的上界

    通配符也有上界,可以限制传入的类型必须是上界这个类或者是这个类的子类。

    基本语法:


    //可以传入的实参类型是Number或者Number的子类

    例如:

    public static void printAll(ArrayList<? extends Number> list) {
            for (Number n: list) {
                System.out.println(n);
            }
        }
    ログイン後にコピー

    我们对printAll方法的一个形参限制了类型的上界Number,所以在遍历这个顺序表的时候,需要使用Number来接收顺序表中的对象,并且使用该方法时,只能遍历输出Number及其子类的对象。

    public static void main(String[] args) {
            printAll(new ArrayList<Integer>());//ok
            printAll(new ArrayList<Double>());//ok
            printAll(new ArrayList<Float>());//ok
    
            printAll(new ArrayList<String>());//error
        }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    假设有如下几个类:

    class Animal{}
    class Cat extends Animal{}
    class Dog extends Animal{}
    class Bird extends Animal{}
    ログイン後にコピー

    AnimalCat,Dog,Bird类的父类,我们来看一看使用泛型和使用通配符在打印对象结果上会有什么区别?我们对这两者都设置了上界,当打印不同的对象时,到底会调用谁的toString方法。

    	//泛型
        public static <T extends Animal> void printAnimal1(ArrayList<T> list) {
            for (T animal: list) {
                System.out.println(animal);
            }
        }
        //通配符
            public static void printAnimal2(ArrayList<? extends Animal> list) {
            for (Animal animal: list) {
                System.out.println(animal);
            }
        }
    ログイン後にコピー

    我们先来看泛型,使用泛型指定类型后,那么指定什么类型,那它就会输出什么类型的对象,比如你指定顺序表中放的类型是Cat,那么它调用的就是Cat对象的toString方法。

    public static void main(String[] args) {
            Cat cat = new Cat();
            Dog dog = new Dog();
            Bird bird = new Bird();
    
            //泛型
            ArrayList<Cat> list1 = new ArrayList<>();
            ArrayList<Dog> list2 = new ArrayList<>();
            ArrayList<Bird> list3 = new ArrayList<>();
            list1.add(cat);
            list2.add(dog);
            list3.add(bird);
            printAnimal1(list1);//Cat
            printAnimal1(list2);//Dog
            printAnimal1(list3);//Bird
        }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    再来看一看通配符,使用通配符是规定能够使用Animal及其子类,不伦你传入哪一个子类对象,都是父类的引用接收,但是具体哪一个子类,并不清楚。

    public static void main(String[] args) {
            Cat cat = new Cat();
            Dog dog = new Dog();
            Bird bird = new Bird();
    
            //通配符
            ArrayList<Cat> list1 = new ArrayList<>();
            ArrayList<Dog> list2 = new ArrayList<>();
            ArrayList<Bird> list3 = new ArrayList<>();
            list1.add(cat);
            list2.add(dog);
            list3.add(bird);
            printAnimal2(list1);//Cat
            printAnimal2(list2);//Dog
            printAnimal2(list3);//Bird
        }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    父类引用接收子类对象发生了向上转型,当打印父类引用的子类对象时,会优先使用子类的toString方法,在介绍多态的时候也讲过这个问题,所以输出结果与使用泛型是一样的,但是泛型和通配符的效果是不一样的,泛型是你传入什么类型,那这个类就会持有什么类型的对象,而通配符是规定一个范围,规定你能够传哪一些类型。

    通配符的上界是支持如下的父子类关系的,而泛型的上界不支持:

    MyArrayList 是 MyArrayList 或者 MyArrayList的父类类型
    MyArrayList<?> 是 MyArrayList 的父类型

    对于通配符的上界有个特点,先说结论,使用通配符上界可以读取数据,但是并不适合写入数据,因为不能确定类所持有的对象具体是什么。

    public static void main(String[] args) {
            ArrayList<Integer> arrayList1 = new ArrayList<>();
            ArrayList<Double> arrayList2 = new ArrayList<>();
            arrayList1.add(10);
            List<? extends Number> list = arrayList1;
            System.out.println(list.get(0));//ok
            Integer = list.get(0);//error因为不能确定list所持有的对象具体是什么
            list.add(2);//error因为不能确定list所持有的对象具体是什么,为了安全,这种情况Java不允许插入元素
        }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    因为从list获取的对象类型一定Number或者Number的子类,所以可以使用Number引用来获取元素,但是插入元素时你并不能确定它到底是哪一种类型,为了安全,使用通配符上界的list不允许插入元素。

    2.3通配符的下界

    与泛型不同,通配符可以拥有下界,语法层面上与通配符的上界的区别是讲关键字extends改为super


    <? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型

    既然是下界那么通配符下界与上界对传入类的规定是相反的,即规定一个泛型类只能传入下界的这个类类型或者这个类的父类类型。比如<? super Integer>代表 可以传入的实参的类型是Integer或者Integer的父类类型(如NumberObject

    public static void printAll(ArrayList<? super Number> list) {
            for (Object n: list) {			//此处只能使用Object接收,因为传入的类是Number或者是Number的父类
                System.out.println(n);
            }
        }
    ログイン後にコピー
    public static void main(String[] args) {
            printAll(new ArrayList<Number>());//ok
            printAll(new ArrayList<Object>());//ok
    
            printAll(new ArrayList<Double>());//error
            printAll(new ArrayList<String>());//error
            printAll(new ArrayList<Integer>());//error
        }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    同理通配符的下界也是满足像下面这种父子类关系的。

    MyArrayList<? super Integer> 是 MyArrayList的父类类型
    MyArrayList<?> 是 MyArrayList<? super Integer>的父类类型

    总结: ?? extends ....? super ....的父类,看通配符之间的父子类关系,最关键的是看通配符所“规定的”范围,判断父子类是根据这个范围来判断的。

    通配符的下界也有一个特点,那就是它能够允许写入数据,当然能够写入的数据对象是下界以及下界的子类,但是并不擅长读数据,与通配符的上界相反。

    public static void main(String[] args) {
            ArrayList<? super Animal> list = new ArrayList<Animal>(); 
            ArrayList<? super Animal> list2 = new ArrayList<Cat>();//编译报错,list2只能引用Animal或者Animal父类类型的list
            list.add(new Animal());//添加元素时,只要添加的元素的类型是Animal或者Animal的子类就可以
            list.add(new Cat());
            Object s2 = list.get(0);//可以
            
            ArrayList<? super Animal> list3 = new ArrayList<Object>();
            Cat s1 = list3.get(0);//error因为构造对象时可以构造Animal父类类型的ArrayList,取出的对象不一定是Animal或者Animal的子类
        }
    ログイン後にコピー

    Java のジェネリックスとワイルドカードの分析例

    对于这个栗子添加元素时,只要添加的元素的类型是Animal或者Animal的子类就可以,获取元素时,只能使用Object引用接收,不能使用其他的引用接收,因为因为构造对象时可以构造Animal父类类型的ArrayList,虽然可以插入Animal以及其子类对象,但取出的对象不能保证是Animal或者Animal的子类。

    以上がJava のジェネリックスとワイルドカードの分析例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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 つの異なるジェネレーターについて例を挙げて説明します。

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

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

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

    Java の Weka へのガイド。ここでは、weka 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