1 /* 2 * Copyright (c) 2022, 2025, 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 8345438 8356551 8349754 26 * @summary Test valid placements of super()/this() in constructors 27 * @run main SuperInitGood 28 * @build InitializationWarningTester 29 * @run main InitializationWarningTester SuperInitGood SuperInitGoodWarnings.out 30 */ 31 32 import java.util.concurrent.atomic.AtomicReference; 33 34 public class SuperInitGood { 35 36 SuperInitGood(Object obj) { 37 } 38 39 SuperInitGood(int x) { 40 } 41 42 // Default constructor provided by compiler 43 static class Test0 { 44 } 45 46 // No explicit calls to this()/super() 47 static class Test1 { 48 Test1() { 49 } 50 51 Test1(int a) { 52 this.hashCode(); 53 } 54 } 55 56 // Explicit calls to this()/super() 57 static class Test2<T> { 58 static int i; 59 Test2() { 60 this(0); 61 } 62 Test2(int i) { 63 Test2.i = i; 64 super(); 65 } 66 Test2(T obj) { 67 this(java.util.Objects.hashCode(obj)); 68 } 69 public T get() { 70 return null; 71 } 72 } 73 74 // Explicit this()/super() with stuff in front 75 static class Test3 { 76 int x; 77 final int y; 78 final int z; 79 80 Test3() { 81 new Object().hashCode(); 82 new Object().hashCode(); 83 super(); 84 this.x = new Object().hashCode(); 85 this.y = new Object().hashCode() % 17; 86 this.z = this.x + this.y; 87 } 88 } 89 90 // Reference within constructor to outer class that's also my superclass 91 class Test5 extends SuperInitGood { 92 Test5(Object obj) { 93 if (obj == null) 94 throw new IllegalArgumentException(); 95 super(SuperInitGood.this); // NOT a 'this' reference 96 } 97 } 98 99 // Initialization blocks 100 class Test6 { 101 final long startTime; 102 final int x; 103 { 104 this.x = 12; 105 } 106 Test6() { 107 long now = System.nanoTime(); 108 long then = now + 1000000L; 109 while (System.nanoTime() < then) { 110 try { 111 Thread.sleep(1); 112 } catch (InterruptedException e) { 113 Thread.currentThread().interrupt(); 114 break; 115 } 116 } 117 super(); 118 this.startTime = now; 119 } 120 } 121 122 // Mix up inner classes, proxies, and super() calls 123 // Copied mostly from UnverifiableInitForNestedLocalClassTest.java 124 public static void test7(final String arg) { 125 final String inlined = " inlined "; 126 class LocalClass { 127 String m() { 128 return "LocalClass " + arg + inlined; 129 } 130 131 class SubClass extends LocalClass { 132 @Override 133 String m() { 134 return "SubClass " + arg + inlined; 135 } 136 } 137 138 class SubSubClass extends SubClass { 139 @Override 140 String m() { 141 return "SubSubClass " + arg + inlined; 142 } 143 } 144 145 class AnotherLocal { 146 class AnotherSub extends LocalClass { 147 AnotherSub() { 148 } 149 AnotherSub(int x) { 150 this((char)x); 151 } 152 AnotherSub(char y) { 153 super(); 154 } 155 @Override 156 String m() { 157 return "AnotherSub " + arg + inlined; 158 } 159 } 160 } 161 } 162 } 163 164 // Anonymous inner class 165 public static void test8() { 166 new Test2<Byte>(null) { 167 @Override 168 public Byte get() { 169 return (byte)-1; 170 } 171 }; 172 } 173 174 // Qualified super() invocation 175 public static class Test9 extends Test5 { 176 177 public Test9(SuperInitGood implicit, Object obj) { 178 obj.hashCode(); 179 implicit.super(obj); 180 } 181 } 182 183 // Copied from WhichImplicitThis6 184 public static class Test10 { 185 private int i; 186 public Test10(int i) {} 187 public class Sub extends Test10 { 188 public Sub() { 189 super(i); // i is not inherited, so it is the enclosing i 190 } 191 } 192 } 193 194 // Two constructors where only one invokes super() 195 public static class Test11 { 196 public Test11() { 197 } 198 public Test11(int x) { 199 super(); 200 } 201 } 202 203 // Nested version of the previous test 204 public static class Test12 { 205 Test12() { 206 class Sub { 207 public Sub() { 208 } 209 public Sub(int j) { 210 super(); 211 } 212 } 213 } 214 } 215 216 // Nested super()'s requiring initialization code appended 217 public static class Test13 extends SuperInitGood { 218 final int x = new Object().hashCode(); 219 Test13() { 220 super(new Object() { 221 public void foo() { 222 class Bar { 223 final int y = new Object().hashCode(); 224 Bar() { 225 super(); 226 } 227 Bar(int ignored) { 228 } 229 } 230 } 231 }); 232 } 233 } 234 235 // Initializer in initializer block 236 public static class Test14 { 237 final int x; // initialized in constructor 238 final int y; // initialized in initialization block 239 final int z = 13; // initialized with intializer value 240 public Test14() { 241 this(0); 242 } 243 public Test14(boolean z) { 244 this.x = z ? 1 : 0; 245 } 246 public Test14(int x) { 247 super(); 248 this.x = x; 249 } 250 { 251 this.y = -1; 252 } 253 } 254 255 // Qualified super() invocation with superclass instance 256 public static class Test15 { 257 258 final String name; 259 260 public Test15(String name) { 261 this.name = name; 262 } 263 264 public class Test15b extends Test15 { 265 266 public Test15b(String name) { 267 super(name); 268 } 269 270 public String getName() { 271 return Test15.this.name; 272 } 273 } 274 } 275 276 public static class Test15c extends Test15.Test15b { 277 public Test15c(Test15 a, String name) { 278 a.super(name); 279 } 280 } 281 282 // Mixing up outer instances, proxies, and initializers 283 public static class Test16 { 284 285 final String x = String.valueOf(new Object().hashCode()); 286 287 public void run() { 288 289 final String y = String.valueOf(new Object().hashCode()); 290 291 class Sub { 292 293 final String z; 294 295 Sub(String z, int ignored) { 296 this(z, (float)ignored); 297 } 298 299 Sub(String z, float ignored) { 300 this.z = z; 301 } 302 303 Sub(String z, byte ignored) { 304 super(); 305 this.z = z; 306 } 307 308 Sub(String z, char ignored) { 309 this(z, (int)ignored); 310 } 311 312 String x() { 313 return x; 314 } 315 316 String y() { 317 return y; 318 } 319 320 String z() { 321 return z; 322 } 323 } 324 325 final String z = String.valueOf(new Object().hashCode()); 326 327 final Sub[] subs = new Sub[] { 328 new Sub(z, 1), 329 new Sub(z, -1), 330 new Sub(z, (float)0), 331 new Sub(z, (byte)0), 332 new Sub(z, (char)0) 333 }; 334 335 for (int i = 0; i < subs.length; i++) { 336 //System.err.println("i = " + i); 337 final Sub sub = subs[i]; 338 final String subx = sub.x(); 339 final String suby = sub.y(); 340 final String subz = sub.z(); 341 if (!x.equals(subx)) 342 throw new RuntimeException("x=" + x + " but sub[" + i + "].x()=" + subx); 343 if (!y.equals(suby)) 344 throw new RuntimeException("y=" + y + " but sub[" + i + "].y()=" + suby); 345 if (!z.equals(subz)) 346 throw new RuntimeException("z=" + z + " but sub[" + i + "].z()=" + subz); 347 } 348 } 349 } 350 351 // Records 352 public class Test17 { 353 354 record Rectangle(float length, float width) { } 355 356 record StringHolder(String string) { 357 StringHolder { 358 java.util.Objects.requireNonNull(string); 359 } 360 } 361 362 record ValueHolder(int value) { 363 ValueHolder(float x) { 364 if (Float.isNaN(x)) 365 throw new IllegalArgumentException(); 366 this((int)x); 367 } 368 } 369 } 370 371 // Exceptions thrown by initializer block 372 public static class Test18 extends AtomicReference<Object> { 373 374 { 375 if ((this.get().hashCode() % 3) == 0) 376 throw new MyException(); 377 } 378 379 public Test18(Object obj) throws MyException { 380 super(obj); 381 } 382 383 public Test18(boolean fail) throws MyException { 384 Object obj; 385 for (obj = new Object(); true; obj = new Object()) { 386 if (((obj.hashCode() % 3) == 0) != fail) 387 continue; 388 break; 389 } 390 this(obj); 391 } 392 393 public static class MyException extends Exception { 394 } 395 } 396 397 // super()/this() within outer try block but inside inner class 398 public static class Test19 { 399 public Test19(int x) { 400 try { 401 new Test1(x) { 402 @Override 403 public int hashCode() { 404 return x ^ super.hashCode(); 405 } 406 }; 407 } catch (StackOverflowError e) { 408 // ignore 409 } 410 } 411 } 412 413 // we allow 'this' reference prior to super() for field assignments only 414 public static class Test20 { 415 private int x; 416 public Test20(short x) { 417 x = x; 418 super(); 419 } 420 public Test20(int x) { 421 this.x = x; 422 super(); 423 } 424 public Test20(char x) { 425 Test20.this.x = x; 426 super(); 427 } 428 public Test20(byte y) { 429 x = y; 430 this((int)y); 431 this.x++; 432 } 433 } 434 435 // allow creating and using local and anonymous classes before super() 436 // they will not have enclosing instances though 437 public static class Test21 { 438 public Test21(int x) { 439 Runnable r = new Runnable() { 440 public void run() { 441 this.hashCode(); 442 } 443 }; 444 r.run(); 445 super(); 446 r.run(); 447 } 448 public Test21(float x) { 449 class Foo { 450 public void bar() { 451 this.hashCode(); 452 } 453 }; 454 new Foo().bar(); 455 super(); 456 new Foo().bar(); 457 } 458 } 459 460 // Lambdas within constructors (JDK-8345438) 461 public static class Test22 { 462 public Test22() { 463 Runnable r = () -> System.out.println(); 464 super(); 465 r.run(); 466 } 467 public Test22(int x) { 468 Runnable r = () -> System.out.println(); 469 r.run(); 470 super(); 471 } 472 public Test22(char x) { 473 Runnable r = () -> { 474 class A { 475 A() { 476 return; 477 } 478 A(int x) { 479 Runnable r2 = () -> { 480 return; 481 }; 482 this(); 483 r2.run(); 484 } 485 A(char x) { 486 this(0); 487 } 488 } 489 return; 490 }; 491 r.run(); 492 super(); 493 } 494 } 495 496 // Receiver parameter syntax (JDK-8356551) 497 public static class Test23 { 498 public Test23() { 499 class Local { 500 Local(Test23 Test23.this) { 501 } 502 } 503 super(); 504 new Local(); 505 } 506 } 507 508 // Test for JDK-8349754 509 public static class Test24 { 510 private int i; 511 class Sub extends Test24 { 512 Sub() { 513 i = 3; // here "i" refers to "Test23.this.i", not "this.i" - so it's OK 514 super(); 515 } 516 } 517 } 518 519 public static class Test25 { 520 public Test25(Object o) {} 521 522 class Sub extends Test25 { 523 public Sub() { 524 super(new Object() { 525 void foo() { 526 getClass(); 527 } 528 }); 529 } 530 } 531 } 532 533 public static void main(String[] args) { 534 new Test0(); 535 new Test1(); 536 new Test1(7); 537 new Test2<Byte>(); 538 new Test2<>(args); 539 new Test3(); 540 new SuperInitGood(3).new Test5(3); 541 new SuperInitGood(3).new Test6(); 542 SuperInitGood.test7("foo"); 543 SuperInitGood.test8(); 544 new Test9(new SuperInitGood(5), "abc"); 545 new Test10(7); 546 new Test11(9); 547 new Test12(); 548 new Test13(); 549 Test14 t14 = new Test14(); 550 assert t14.x == 0 && t14.y == -1 && t14.z == 13; 551 t14 = new Test14(7); 552 assert t14.x == 7 && t14.y == -1 && t14.z == 13; 553 new Test15c(new Test15("foo"), "bar"); 554 new Test16().run(); 555 new Test17.StringHolder("foo"); 556 try { 557 new Test17.StringHolder(null); 558 throw new Error(); 559 } catch (NullPointerException e) { 560 // expected 561 } 562 try { 563 new Test18(true); 564 assert false : "expected exception"; 565 } catch (Test18.MyException e) { 566 // expected 567 } 568 try { 569 new Test18(false); 570 } catch (Test18.MyException e) { 571 assert false : "unexpected exception: " + e; 572 } 573 new Test19(123); 574 new Test20(123); 575 new Test21((int)123); 576 new Test21((float)123); 577 new Test22('x'); 578 new Test23(); 579 new Test24(); 580 new Test25(null); 581 } 582 }