Узагальнення в мові Java Узагальнення (generics) – це параметризовані типи. Узагальнені класи Узагальнені об’єкти
Приклади використання узагальнень class Gen { T ob; Gen(T o) { ob = o; } // Return ob. T getob() { return ob; } // Show type of T. void show. Type() { System. out. println("Type of T is " + ob. get. Class(). get. Name()); } } class Gen. Demo { public static void main(String args[]) { Gen i. Ob; i. Ob = new Gen(88); i. Ob. show. Type(); int v = i. Ob. getob(); System. out. println("value: " + v); System. out. println(); Gen str. Ob = new Gen("Generics Test"); str. Ob. show. Type(); String str = str. Ob. getob(); System. out. println("value: " + str); } } Type of T is java. lang. Integer value: 88 Type of T is java. lang. String value: Generics Test
Основні правила роботи із узагальненнями 1. Узагальнення працюють тільки з об’єктами Gen str. Ob = new Gen(53); // Помилка!!! 2. Узагальнені типи відрізняються в залежності від типів -аргументів i. Ob = str. Ob; // Неправильно!!!
Узагальнення підвищують безпеку типів class Non. Gen { Object ob; Non. Gen(Object o) { ob = o; } Object getob() { return ob; } void show. Type() { System. out. println("Type of ob is " + ob. get. Class(). get. Name()); } } class Non. Gen. Demo { public static void main(String args[]) { Non. Gen i. Ob; i. Ob = new Non. Gen(88); i. Ob. show. Type(); int v = (Integer) i. Ob. getob(); System. out. println("value: " + v); System. out. println(); Non. Gen str. Ob = new Non. Gen("Non-Generics Test"); str. Ob. show. Type(); String str = (String) str. Ob. getob(); System. out. println("value: " + str); i. Ob = str. Ob; v = (Integer) i. Ob. getob(); // run-time error! } }
Узагальнений клас з двома параметрами типу class Two. Gen { T ob 1; V ob 2; Two. Gen(T o 1, V o 2) { ob 1 = o 1; ob 2 = o 2; } void show. Types() { System. out. println("Type of T is " + ob 1. get. Class(). get. Name()); System. out. println("Type of V is " + ob 2. get. Class(). get. Name()); } T getob 1() { return ob 1; } V getob 2() { return ob 2; } } // Demonstrate Two. Gen. class Simp. Gen { public static void main(String args[]) { Two. Gen tg. Obj = new Two. Gen(88, "Generics"); tg. Obj. show. Types(); int v = tg. Obj. getob 1(); System. out. println("value: " + v); String str = tg. Obj. getob 2(); System. out. println("value: " + str); } } Type of T is java. lang. Integer Type of V is java. lang. String value: 88 value: Generics Test
Загальна форма узагальненого класу class ім’я_класу<список_параметрів_типів> { // … } ім’я_класу <список_аргументів_типів> ім’я_змінної = new ім’я_класу <список_аргументів_типів>( список_аргументів_констант);
Обмежені типи class Stats { T[] nums; Stats(T[] o) { nums = o; } double average() { double sum = 0. 0; for(int i=0; i < nums. length; i++) sum += nums[i]. double. Value(); return sum / nums. length; } } class Bounds. Demo { public static void main(String args[]) { Integer inums[] = { 1, 2, 3, 4, 5 }; Stats iob = new Stats(inums); double v = iob. average(); System. out. println("iob average is " + v); Double dnums[] = { 1. 1, 2. 2, 3. 3, 4. 4, 5. 5 }; Stats dob = new Stats(dnums); double w = dob. average(); System. out. println("dob average is " + w); // String strs[] = { "1", "2", "3", "4", "5" }; // Stats strob = new //Stats(strs); // double x = strob. average(); // System. out. println("strob average is " + v); } }
Використання шаблонних аргументів class Stats { T[] nums; Stats(T[] o) { nums = o; } double average() { double sum = 0. 0; for(int i=0; i < nums. length; i++) sum += nums[i]. double. Value(); return sum / nums. length; } boolean same. Avg(Stats > ob) { if(average() == ob. average()) return true; return false; } } class Wildcard. Demo { public static void main(String args[]) { Integer inums[] = { 1, 2, 3, 4, 5 }; Stats iob = new Stats(inums); double v = iob. average(); System. out. println("iob average is " + v); Double dnums[] = { 1. 1, 2. 2, 3. 3, 4. 4, 5. 5 }; Stats dob = new Stats(dnums); double w = dob. average(); System. out. println("dob average is " + w); Float fnums[] = { 1. 0 F, 2. 0 F, 3. 0 F, 4. 0 F, 5. 0 F }; Stats fob = new Stats(fnums); double x = fob. average(); System. out. println("fob average is " + x); System. out. print("Averages of iob and dob "); if(iob. same. Avg(dob)) System. out. println("are the same. "); else System. out. println("differ. "); System. out. print("Averages of iob and fob "); if(iob. same. Avg(fob)) System. out. println("are the same. "); else System. out. println("differ. "); } } iob average is 3. 0 dob average is 3. 3 fob average is 3. 0 Averages of iob and dob differ. Averages of iob and fob are the same.
Обмежені шаблони (1) class Two. D { int x, y; Two. D(int a, int b) { x = a; y = b; } } class Three. D extends Two. D { int z; Three. D(int a, int b, int c) { super(a, b); z = c; } } class Four. D extends Three. D { int t; Four. D(int a, int b, int c, int d) { super(a, b, c); t = d; } } class Coords { T[] coords; Coords(T[] o) { coords = o; } } class Bounded. Wildcard { static void show. XY(Coords > c) { System. out. println("X Y Coordinates: "); for(int i=0; i < c. coords. length; i++) System. out. println(c. coords[i]. x + " " + c. coords[i]. y); System. out. println(); } static void show. XYZ(Coords extends Three. D> c) { System. out. println("X Y Z Coordinates: "); for(int i=0; i < c. coords. length; i++) System. out. println(c. coords[i]. x + " " + c. coords[i]. y + " " + c. coords[i]. z); System. out. println(); }
Обмежені шаблони (2) static void show. All(Coords extends Four. D> c) { System. out. println("X Y Z T Coordinates: "); for(int i=0; i < c. coords. length; i++) System. out. println(c. coords[i]. x + " " + c. coords[i]. y + " " + c. coords[i]. z + " " + c. coords[i]. t); System. out. println(); Coords tdlocs = new Coords(td); System. out. println("Contents of tdlocs. "); show. XY(tdlocs); // OK, is a Two. D // show. XYZ(tdlocs); // Error, not a Three. D // show. All(tdlocs); // Error, not a Four. D // Now, create some Four. D objects. Four. D fd[] = { new Four. D(1, 2, 3, 4), new Four. D(6, 8, 14, 8), new Four. D(22, 9, 4, 9), new Four. D(3, -23, 17) }; } public static void main(String args[]) { Two. D td[] = { new Two. D(0, 0), new Two. D(7, 9), new Two. D(18, 4), new Two. D(-1, -23) }; Coords fdlocs = new Coords(fd); } } System. out. println("Contents of fdlocs. "); // These are all OK. show. XY(fdlocs); show. XYZ(fdlocs); show. All(fdlocs);
Узагальнені методи class Gen. Meth. Demo { System. out. println(); // Determine if an object is in an array. static boolean is. In(T x, V[] y) { for(int i=0; i < y. length; i++) if(x. equals(y[i])) return true; return false; } public static void main(String args[]) { // Use is. In() on Integers. Integer nums[] = { 1, 2, 3, 4, 5 }; if(is. In(2, nums)) System. out. println("2 is in nums"); if(!is. In(7, nums)) System. out. println("7 is not in nums"); // Use is. In() on Strings. String strs[] = { "one", "two", "three", "four", "five" }; if(is. In("two", strs)) System. out. println("two is in strs"); if(!is. In("seven", strs)) System. out. println("seven is not in strs"); // Opps! Won't compile! Types must be compatible. // if(is. In("two", nums)) // System. out. println("two is in strs"); } }
Узагальнені конструктори class Gen. Cons { private double val; Gen. Cons(T arg) { val = arg. double. Value(); } void showval() { System. out. println("val: " + val); } } class Gen. Cons. Demo { public static void main(String args[]) { Gen. Cons test = new Gen. Cons(100); Gen. Cons test 2 = new Gen. Cons(123. 5 F); test. showval(); test 2. showval(); } } val: 100. 0 val: 123. 5
Узагальнені інтерфейси interface Min. Max> { T min(); T max(); } // Now, implement Min. Max class My. Class> implements Min. Max { T[] vals; My. Class(T[] o) { vals = o; } // Return the minimum value in vals. public T min() { T v = vals[0]; for(int i=1; i < vals. length; i++) if(vals[i]. compare. To(v) < 0) v = vals[i]; return v; } // Return the maximum value in vals. public T max() { T v = vals[0]; for(int i=1; i < vals. length; i++) if(vals[i]. compare. To(v) > 0) v = vals[i]; return v; } } class Gen. IFDemo { public static void main(String args[]) { Integer inums[] = {3, 6, 2, 8, 6 }; Character chs[] = {'b', 'r', 'p', 'w' }; My. Class iob = new My. Class(inums); My. Class cob = new My. Class(chs); System. out. println("Max value in inums: " + iob. max()); System. out. println("Min value in inums: " + iob. min()); System. out. println("Max value in chs: " + cob. max()); System. out. println("Min value in chs: " + cob. min()); } }
Raw-типи і успадкований код class Gen { T ob; // declare an object of type T // Pass the constructor a reference to // an object of type T. Gen(T o) { ob = o; } // Return ob. T getob() { return ob; } } // Demonstrate raw type. class Raw. Demo { public static void main(String args[]) { // Create a Gen object for Integers. Gen i. Ob = new Gen(88); // Create a Gen object for Strings. Gen str. Ob = new Gen("Generics Test"); // Create a raw-type Gen object and give it // a Double value. Gen raw = new Gen(new Double(98. 6)); // Cast here is necessary because type is unknown. double d = (Double) raw. getob(); System. out. println("value: " + d); // The use of a raw type can lead to run-time. // exceptions. Here are some examples. // The following cast causes a run-time error! // int i = (Integer) raw. getob(); // run-time error // This assigment overrides type safety. str. Ob = raw; // OK, but potentially wrong // String str = str. Ob. getob(); // run-time error // This assingment also overrides type safety. raw = i. Ob; // OK, but potentially wrong // d = (Double) raw. getob(); // run-time error } }
Ієрархія узагальнених класів Використання узагальненого суперкласу class Gen { T ob; // declare an object of type T // Pass the constructor a reference to // an object of type T. Gen(T o) { ob = o; } // Return ob. T getob() { return ob; } } // A subclass of Gen that defines a second // type parameter, called V. class Gen 2 extends Gen { V ob 2; Gen 2(T o, V o 2) { super(o); ob 2 = o 2; } V getob 2() { return ob 2; } } // Create an object of type Gen 2. class Hier. Demo { public static void main(String args[]) { // Create a Gen 2 object for String and Integer. Gen 2 x = new Gen 2("Value is: ", 99); } } System. out. print(x. getob()); System. out. println(x. getob 2()); Value is: 99
Ієрархія узагальнених класів Узагальнений підклас class Non. Gen { int num; Non. Gen(int i) { num = i; } int getnum() { return num; } } // Create a Gen object. class Hier. Demo 2 { public static void main(String args[]) { // Create a Gen object for String. Gen w = new Gen("Hello", 47); } // A generic subclass Gen extends Non. Gen { T ob; // declare an object of type T // Pass the constructor a reference to // an object of type T. Gen(T o, int i) { super(i); ob = o; } // Return ob. T getob() { return ob; } } } System. out. print(w. getob() + " "); System. out. println(w. getnum()); Hello 47
Порівняння типів узагальненої ієрархії підчас виконання (1) instanceof class Gen { T ob; Gen(T o) { ob = o; } // Return ob. T getob() { return ob; } } // A subclass of Gen. class Gen 2 extends Gen { Gen 2(T o) { super(o); } } // Demonstrate run-time type ID implications of generic // class hierarchy. class Hier. Demo 3 { public static void main(String args[]) { // Create a Gen object for Integers. Gen i. Ob = new Gen(88); // Create a Gen 2 object for Integers. Gen 2 i. Ob 2 = new Gen 2(99); // Create a Gen 2 object for Strings. Gen 2 str. Ob 2 = new Gen 2("Generics Test"); // See if i. Ob 2 is some form of Gen 2. if(i. Ob 2 instanceof Gen 2 >) System. out. println("i. Ob 2 is instance of Gen 2"); // See if i. Ob 2 is some form of Gen. if(i. Ob 2 instanceof Gen >) System. out. println("i. Ob 2 is instance of Gen"); System. out. println(); // See if str. Ob 2 is a Gen 2. if(str. Ob 2 instanceof Gen 2 >) System. out. println("str. Ob is instance of Gen 2"); // See if str. Ob 2 is a Gen. if(str. Ob 2 instanceof Gen >) System. out. println("str. Ob is instance of Gen"); System. out. println();
Порівняння типів узагальненої ієрархії підчас виконання (2) // See if i. Ob is an instance of Gen 2, which it is not. if(i. Ob instanceof Gen 2 >) System. out. println("i. Ob is instance of Gen 2"); // See if i. Ob is an instance of Gen, which it is. if(i. Ob instanceof Gen >) System. out. println("i. Ob is instance of Gen"); // The following can't be compiled because // generic type info does not exist at run-time. // if(i. Ob 2 instanceof Gen 2) // System. out. println("i. Ob 2 is instance of Gen 2"); } } i. Ob 2 is instance of Gen 2 i. Ob 2 is instance of Gen str. Ob 2 instanceof Gen 2 str. Ob 2 instanceof Gen i. Ob is instance of Gen 2
Приведення типів (Gen) i. Ob 2 // допустимо (Gen) i. Ob 2 // недопустимо
Перевизначення методів в узагальненому класі class Gen { T ob; // declare an object of type T // Pass the constructor a reference to // an object of type T. Gen(T o) { ob = o; } // Return ob. T getob() { System. out. print("Gen's getob(): " ); return ob; } } // A subclass of Gen that overrides getob(). class Gen 2 extends Gen { Gen 2(T o) { super(o); } // Override getob(). T getob() { System. out. print("Gen 2's getob(): "); return ob; } } // Demonstrate generic method override. class Override. Demo { public static void main(String args[]) { // Create a Gen object for Integers. Gen i. Ob = new Gen(88); // Create a Gen 2 object for Integers. Gen 2 i. Ob 2 = new Gen 2(99); // Create a Gen 2 object for Strings. Gen 2 str. Ob 2 = new Gen 2("Generics Test"); } } System. out. println(i. Ob. getob()); System. out. println(i. Ob 2. getob()); System. out. println(str. Ob 2. getob()); Gen's getob(): 88 Gen 2's getob(): 99 Gen 2's getob(): Generics Test
Очистка class Gen { T ob; // here, T will be replaced by Object Gen(T o) { ob = o; } // Return ob. T getob() { return ob; } } // Here, T is bound by String. class Gen. Str { T str; // here, T will be replaced by String Gen. Str(T o) { str = o; } T getstr() { return str; } } class Gen. Type. Demo { public static void main(String args[]) { Gen i. Ob = new Gen(99); Gen f. Ob = new Gen(102. 2 F); } } System. out. println(i. Ob. get. Class(). get. Name()); System. out. println(f. Ob. get. Class(). get. Name()); Gen
Методи-мости (bridge method) class Gen { T ob; // declare an object of type T // Pass the constructor a reference to // an object of type T. Gen(T o) { ob = o; } // Return ob. T getob() { return ob; } // A String-specific override of getob(). String getob() { System. out. print("You called String getob(): "); return ob; } } // Demonstrate a situation that requires a bridge method. class Bridge. Demo { public static void main(String args[]) { // Create a Gen 2 object for Strings. Gen 2 str. Ob 2 = new Gen 2("Generics Test"); } // A subclass of Gen. class Gen 2 extends Gen { Gen 2(String o) { super(o); } } } System. out. println(str. Ob 2. getob());
Помилки неоднозначності (ambiquity) class My. Gen. Class { T ob 1; V ob 2; //. . . // These two overloaded methods are ambiguous // and will not compile. void set(T o) { ob 1 = o; } void set(V o) { ob 2 = o; } } 1. My. Gen. Class obj = My. Gen. Class () 2. void set(Object o) { // …
Обмеження у використанні узагальнень Заборонено створювати екземпляр типу параметра Обмеження узагальнених масивів class Gen { class Gen { T ob; Gen() { T vals[]; // OK ob = new T(); // Illegal!!! Gen(T o, T[] nums) { } ob = o; // This statement is illegal. } // vals = new T[10]; // can't create an array of T Обмеження на статичні члени // But, this statement is OK. class Wrong { vals = nums; // OK to assign reference to existent array // Wrong, no static variables of type T. } static T ob; } class Gen. Arrays { public static void main(String args[]) { // Wrong, no static method can use T. Integer n[] = { 1, 2, 3, 4, 5 }; static T getob() { Gen i. Ob = new Gen(50, n); return ob; // Can't create an array of type-specific generic references. } // Gen gens[] = new Gen[10]; // Wrong! // This is OK. Gen > gens[] = new Gen >[10]; // OK // Wrong, no static method can access object } // of type T. } static void showob() { System. out. println(ob); Обмеження узагальнених винятків } Throwable }