24

Class.newInstance was deprecated in Java 9:

clazz.newInstance()

can be replaced by

clazz.getDeclaredConstructor().newInstance()

The problem is that getDeclaredConstructor returns any constructor without regarding the access level.

If I want to replace all occurrences in my code (on different packages/access level) should I use getConstructor to get the public constructor?

the Constructor object of the public constructor that matches the specified parameterTypes

Or can't I bulk replace all occurrences because it needs to be per case (if a public constructor exists and/or if I have the right access level for the class)?

EDIT

getDeclaredConstructor:

   return getConstructor0(parameterTypes, Member.DECLARED);

getConstructor:

   return getConstructor0(parameterTypes, Member.PUBLIC);
Holger
  • 285,553
  • 42
  • 434
  • 765
Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • 1
    If you need to access constructor at different levels, getDeclaredConstructor(s) is the only way out. Can't you use `getDeclaredConstructors​()` (not `getDeclaredConstructor()`) to get all constructors and replace one depending on your logic? – Sukhpal Singh Nov 12 '18 at 07:02
  • 6
    As the deprecation message says, the equivalent code to `clazz.newInstance()` is `clazz.getDeclaredConstructor().newInstance()`. I would assume this means that anywhere you're successfully using `clazz.newInstance()` can be replaced with the recommended code. If you replace `clazz.newInstance()` with `clazz.getConstructor().newInstance()` you're changing the semantics of the code. – Slaw Nov 12 '18 at 07:04
  • 2
    I haven’t tried, but I wouldn’t expect `clazz.newInstance()` to work either if the zero-arg constructor isn’t public — does it?? So what would you be losing in practice by using `clazz.getDeclaredConstructor().newInstance()` instead? – Ole V.V. Nov 12 '18 at 07:22
  • 2
    @OleV.V. Yes, `Class.newInstance()` works with non-public constructors. But it requires you to have the proper access else it throws an `IllegalAccessException` (from some quick, non-exhaustive testing). – Slaw Nov 12 '18 at 07:28
  • 1
    @Slaw Using `getDeclaredConstructor`, How can I be sure getting private constructor won't failed to create `newInstance`? – Ori Marko Nov 12 '18 at 07:29
  • 6
    Related (on the reasons why it was deprecated): https://stackoverflow.com/questions/195321/why-is-class-newinstance-evil – Hulk Nov 12 '18 at 08:09

1 Answers1

27

These two calls invoke the same constructor, the zero-argument constructor:

  1. klass.newInstance()
  2. klass.getDeclaredConstructor().newInstance()

Both perform the same run-time check to verify the caller's access, if the constructor is not public. The only difference is that #2 wraps any checked exceptions instead of directly throwing. Otherwise they are identical and you can replace one with the other.

But this is different:

  1. klass.getConstructor().newInstance()

because it can only return a public constructor. It throws a NoSuchMethodException if the constructor is not public.

So you can't change it to getConstructor() unless you know the constructor is public.

Boann
  • 48,794
  • 16
  • 117
  • 146