1 /* 2 * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 /* 24 * @test 25 * @bug 8194743 26 * @summary Test valid placements of super()/this() in constructors 27 * @enablePreview 28 */ 29 30 import java.util.concurrent.atomic.AtomicReference; 31 32 public class SuperInitGood { 33 34 SuperInitGood(Object obj) { 35 } 36 37 SuperInitGood(int x) { 38 } 39 40 // Default constructor provided by compiler 41 static class Test0 { 42 } 43 44 // No explicit calls to this()/super() 45 static class Test1 { 46 Test1() { 47 } 48 Test1(int a) { 49 this.hashCode(); 50 } 51 } 52 53 // Explicit calls to this()/super() 54 static class Test2<T> { 55 static int i; 56 Test2() { 57 this(0); 58 } 59 Test2(int i) { 60 Test2.i = i; 61 super(); 62 } 63 Test2(T obj) { 64 this(java.util.Objects.hashCode(obj)); 65 } 66 public T get() { 67 return null; 68 } 69 } 70 71 // Explicit this()/super() with stuff in front 72 static class Test3 { 73 int x; 74 final int y; 75 final int z; 76 77 Test3() { 78 new Object().hashCode(); 79 new Object().hashCode(); 80 super(); 81 this.x = new Object().hashCode(); 82 this.y = new Object().hashCode() % 17; 83 this.z = this.x + this.y; 84 } 85 } 86 87 // Reference within constructor to outer class that's also my superclass 88 class Test5 extends SuperInitGood { 89 Test5(Object obj) { 90 if (obj == null) 91 throw new IllegalArgumentException(); 92 super(SuperInitGood.this); // NOT a 'this' reference 93 } 94 } 95 96 // Initialization blocks 97 class Test6 { 98 final long startTime; 99 final int x; 100 { 101 this.x = 12; 102 } 103 Test6() { 104 long now = System.nanoTime(); 105 long then = now + 1000000L; 106 while (System.nanoTime() < then) { 107 try { 108 Thread.sleep(1); 109 } catch (InterruptedException e) { 110 Thread.currentThread().interrupt(); 111 break; 112 } 113 } 114 super(); 115 this.startTime = now; 116 } 117 } 118 119 // Mix up inner classes, proxies, and super() calls 120 // Copied mostly from UnverifiableInitForNestedLocalClassTest.java 121 public static void test7(final String arg) { 122 final String inlined = " inlined "; 123 class LocalClass { 124 String m() { 125 return "LocalClass " + arg + inlined; 126 } 127 128 class SubClass extends LocalClass { 129 @Override 130 String m() { 131 return "SubClass " + arg + inlined; 132 } 133 } 134 135 class SubSubClass extends SubClass { 136 @Override 137 String m() { 138 return "SubSubClass " + arg + inlined; 139 } 140 } 141 142 class AnotherLocal { 143 class AnotherSub extends LocalClass { 144 AnotherSub() { 145 } 146 AnotherSub(int x) { 147 this((char)x); 148 } 149 AnotherSub(char y) { 150 super(); 151 } 152 @Override 153 String m() { 154 return "AnotherSub " + arg + inlined; 155 } 156 } 157 } 158 } 159 } 160 161 // Anonymous inner class 162 public static void test8() { 163 new Test2<Byte>(null) { 164 @Override 165 public Byte get() { 166 return (byte)-1; 167 } 168 }; 169 } 170 171 // Qualified super() invocation 172 public static class Test9 extends Test5 { 173 174 public Test9(SuperInitGood implicit, Object obj) { 175 obj.hashCode(); 176 implicit.super(obj); 177 } 178 } 179 180 // Copied from WhichImplicitThis6 181 public static class Test10 { 182 private int i; 183 public Test10(int i) {} 184 public class Sub extends Test10 { 185 public Sub() { 186 super(i); // i is not inherited, so it is the enclosing i 187 } 188 } 189 } 190 191 // Two constructors where only one invokes super() 192 public static class Test11 { 193 public Test11() { 194 } 195 public Test11(int x) { 196 super(); 197 } 198 } 199 200 // Nested version of the previous test 201 public static class Test12 { 202 Test12() { 203 class Sub { 204 public Sub() { 205 } 206 public Sub(int j) { 207 super(); 208 } 209 } 210 } 211 } 212 213 // Nested super()'s requiring initialization code appended 214 public static class Test13 extends SuperInitGood { 215 final int x = new Object().hashCode(); 216 Test13() { 217 super(new Object() { 218 public void foo() { 219 class Bar { 220 final int y = new Object().hashCode(); 221 Bar() { 222 super(); 223 } 224 Bar(int ignored) { 225 } 226 } 227 } 228 }); 229 } 230 } 231 232 // Initializer in initializer block 233 public static class Test14 { 234 final int x; // initialized in constructor 235 final int y; // initialized in initialization block 236 final int z = 13; // initialized with intializer value 237 public Test14() { 238 this(0); 239 } 240 public Test14(boolean z) { 241 this.x = z ? 1 : 0; 242 } 243 public Test14(int x) { 244 super(); 245 this.x = x; 246 } 247 { 248 this.y = -1; 249 } 250 } 251 252 // Qualified super() invocation with superclass instance 253 public static class Test15 { 254 255 final String name; 256 257 public Test15(String name) { 258 this.name = name; 259 } 260 261 public class Test15b extends Test15 { 262 263 public Test15b(String name) { 264 super(name); 265 } 266 267 public String getName() { 268 return Test15.this.name; 269 } 270 } 271 } 272 273 public static class Test15c extends Test15.Test15b { 274 public Test15c(Test15 a, String name) { 275 a.super(name); 276 } 277 } 278 279 // Mixing up outer instances, proxies, and initializers 280 public static class Test16 { 281 282 final String x = String.valueOf(new Object().hashCode()); 283 284 public void run() { 285 286 final String y = String.valueOf(new Object().hashCode()); 287 288 class Sub { 289 290 final String z; 291 292 Sub(String z, int ignored) { 293 this(z, (float)ignored); 294 } 295 296 Sub(String z, float ignored) { 297 this.z = z; 298 } 299 300 Sub(String z, byte ignored) { 301 super(); 302 this.z = z; 303 } 304 305 Sub(String z, char ignored) { 306 this(z, (int)ignored); 307 } 308 309 String x() { 310 return x; 311 } 312 313 String y() { 314 return y; 315 } 316 317 String z() { 318 return z; 319 } 320 } 321 322 final String z = String.valueOf(new Object().hashCode()); 323 324 final Sub[] subs = new Sub[] { 325 new Sub(z, 1), 326 new Sub(z, -1), 327 new Sub(z, (float)0), 328 new Sub(z, (byte)0), 329 new Sub(z, (char)0) 330 }; 331 332 for (int i = 0; i < subs.length; i++) { 333 //System.err.println("i = " + i); 334 final Sub sub = subs[i]; 335 final String subx = sub.x(); 336 final String suby = sub.y(); 337 final String subz = sub.z(); 338 if (!x.equals(subx)) 339 throw new RuntimeException("x=" + x + " but sub[" + i + "].x()=" + subx); 340 if (!y.equals(suby)) 341 throw new RuntimeException("y=" + y + " but sub[" + i + "].y()=" + suby); 342 if (!z.equals(subz)) 343 throw new RuntimeException("z=" + z + " but sub[" + i + "].z()=" + subz); 344 } 345 } 346 } 347 348 // Records 349 public class Test17 { 350 351 record Rectangle(float length, float width) { } 352 353 record StringHolder(String string) { 354 StringHolder { 355 java.util.Objects.requireNonNull(string); 356 } 357 } 358 359 record ValueHolder(int value) { 360 ValueHolder(float x) { 361 if (Float.isNaN(x)) 362 throw new IllegalArgumentException(); 363 this((int)x); 364 } 365 } 366 } 367 368 // Exceptions thrown by initializer block 369 public static class Test18 extends AtomicReference<Object> { 370 371 { 372 if ((this.get().hashCode() % 3) == 0) 373 throw new MyException(); 374 } 375 376 public Test18(Object obj) throws MyException { 377 super(obj); 378 } 379 380 public Test18(boolean fail) throws MyException { 381 Object obj; 382 for (obj = new Object(); true; obj = new Object()) { 383 if (((obj.hashCode() % 3) == 0) != fail) 384 continue; 385 break; 386 } 387 this(obj); 388 } 389 390 public static class MyException extends Exception { 391 } 392 } 393 394 // super()/this() within outer try block but inside inner class 395 public static class Test19 { 396 public Test19(int x) { 397 try { 398 new Test1(x) { 399 @Override 400 public int hashCode() { 401 return x ^ super.hashCode(); 402 } 403 }; 404 } catch (StackOverflowError e) { 405 // ignore 406 } 407 } 408 } 409 410 // local class declared before super(), but not used until after super() 411 public static class Test20 { 412 public Test20() { 413 class Foo { 414 Foo() { 415 Test20.this.hashCode(); 416 } 417 } 418 super(); 419 new Foo(); 420 } 421 } 422 423 // local class inside super() parameter list 424 public static class Test21 extends AtomicReference<Object> { 425 private int x; 426 public Test21() { 427 super(switch ("foo".hashCode()) { 428 default -> { 429 class Nested {{ System.out.println(x); }} // class is NOT instantiated - OK 430 yield "bar"; 431 } 432 }); 433 } 434 } 435 436 public static void main(String[] args) { 437 new Test0(); 438 new Test1(); 439 new Test1(7); 440 new Test2<Byte>(); 441 new Test2<>(args); 442 new Test3(); 443 new SuperInitGood(3).new Test5(3); 444 new SuperInitGood(3).new Test6(); 445 SuperInitGood.test7("foo"); 446 SuperInitGood.test8(); 447 new Test9(new SuperInitGood(5), "abc"); 448 new Test10(7); 449 new Test11(9); 450 new Test12(); 451 new Test13(); 452 Test14 t14 = new Test14(); 453 assert t14.x == 0 && t14.y == -1 && t14.z == 13; 454 t14 = new Test14(7); 455 assert t14.x == 7 && t14.y == -1 && t14.z == 13; 456 new Test15c(new Test15("foo"), "bar"); 457 new Test16().run(); 458 new Test17.StringHolder("foo"); 459 try { 460 new Test17.StringHolder(null); 461 throw new Error(); 462 } catch (NullPointerException e) { 463 // expected 464 } 465 try { 466 new Test18(true); 467 assert false : "expected exception"; 468 } catch (Test18.MyException e) { 469 // expected 470 } 471 try { 472 new Test18(false); 473 } catch (Test18.MyException e) { 474 assert false : "unexpected exception: " + e; 475 } 476 new Test19(123); 477 new Test20(); 478 new Test21(); 479 } 480 }