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