1

I have just started learning java and I have two basics questions. My main() looks like this:

public class Main {
public static void main(String[] args) {
    Storage<BankAccount> aStorage = new Storage<BankAccount>(); 
    Storage<String> sStorage = new Storage<String>();

    Class baCls = BankAccount.class;
    try {
    Object myAccount = baCls.newInstance();
    aStorage.setValue( myAccount );
    myAccount.deposit( 15 );
    }
    catch ( InstantiationException e ) {
    }
    catch ( IllegalAccessException e ) {
    }
}}

Why do I get these errors:

  • The method deposit(int) is undefined for the type Object
  • The method setValue(BankAccount) in the type Storage is not applicable for the arguments (Object).

After that I tried to replace:

Object myAccount = baCls.newInstance();

with

BankAccount myAccount = baCls.newInstance();

But then I am getting this error:

  • Type mismatch: cannot convert from Object to BankAccount

I know that the right way would be:

BankAccount myAccount = (BankAccount) baCls.newInstance();

But I am not really sure that I understand why... I tried to read about it from a various sources so I have a few theories, but I still cannot wrap my head around this properly. Can someone please help me understand?

P.S. Sorry for posting such a basic question.

2
  • 5
    Is there a reason you're trying to instantiate by using Object#newInstance instead of something like BankAccount myAccount = new BankAccount()? Commented Apr 15, 2016 at 17:25
  • 1
    Not any specific reason, I am just playing around trying to understand the basic concepts of the language : ) Commented Apr 15, 2016 at 17:31

2 Answers 2

9

Doing BankAccount myAccount = baCls.newInstance() invokes reflection to create a new object. Class is generic, but you have not specified the generic type. If you do Class<BankAccount> baCls = BankAccount.class then you shouldn't need to cast.

Java is strongly typed. By declaring an object as object you're saying to the language that this object is just an object: that is it only has the methods and fields found on ALL objects, and nothing more.

By specifying the type, you tell Java what methods and fields you can access, which is why when you write BankAccount myAccount, it allows you to call functions on it.

But baCls.newInstance() creates a new instance of whatever class baCls is. It doesn't know what type of class it is creating since it's a method on the Class class (confusing) itself, so you have to tell Java what class you expect it to return via casting: BankAccount myAccount = (BankAccount) baCls.newInstance();

However, the bigger question is why you are using newInstance in the first place. Is it possible to do:

BankAccount myAccount = new BankAccount();

Reflection is a little advanced for a beginner.

Sign up to request clarification or add additional context in comments.

3 Comments

A subtle but import point: You're not saying that the object has the methods and fields on all objects, and nothing more. You're saying it has all the method sand fields on objects, and we don't know what else it may have. If you downcast the reference to get at those extra methods and fields, the underlying object is totally, completely unchanged -- it doesn't suddenly "get" the methods and fields it didn't have before. All that changes is the compiler's knowledge of those members.
Thank you very much Jason. I understand that BankAccount myAccount = new BankAccount(); would be the best way, I just wanted to play around and understand a little better some of Java's basic concepts. I am still a little confused as to what happens to myAccount when doing this: BankAccount myAccount = baCls.newInstance();
doing BankAccount myAccount = baCls.newInstance() invokes reflection to create a new object. Class is generic, but you have not specified the generic type. If you do Class<BankAccount> baCls = BankAccount.class then you shouldn't need to cast.
2

Because you've defined it via the Object interface, which doesn't know about your object specific methods, such as deposit().

Object myAccount = baCls.newInstance();

Should be...

BankAccount myAccount = (BankAccount)(baCls.newInstance());

Or simply...

BankAccount myAccount = new BankAccount();

Then you can call deposit on it, as that exists in the contract defined by BankAccount, assuming that baCls is indeed a BankAccount. You can check this with instanceof BankAccount beforehand, if you're uncertain of its type.

By way of further explanation...

If I define a class of OperatingSystem, then I subclass that class to be UnixOperatingSystem and WindowsOperatingSystem. Now, obviously there are things that are common, but also specific to each of these computers. But if I do this...

OperatingSystem os = new WindowsOperatingSystem();

Then, I am creating a WindowsOperatingSystem, but only allowing the common OperatingSystem methods to be called, as that's what's defined in that super class by its method signature contract. I could therefore call the shutdown() method perhaps (as any OS should be able to shutdown), but not the runBatchFile("test.bat") method. I would need to declare it explicitly as a WindowsOperatingSystem to be able to call that specific method.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.