简体   繁体   中英

Some classes need initialization and some don't

I already tried to search for an answer on the "using the new keyword" but didn't found an answer on my specific question.

Why do some classes have to be created with the keyword new and some don't

For example :

import java.io.BufferedReader

If you want to use this you have to create a new instance

BufferedReader read = new BufferedReader (..............)

But for example with system.console which also needs an import java.io.console . when you want to use this you can just type Console c = system.console()

i'm a beginner in Java and OO programming and found a couple of this examples troughout my book.

Thx for the help

In java, fields(aka Attributes) are always associated to either instance or to class.

There could be many instances of a class and to create instance you have to use new operator. To access instance related attributes, you will need to create one and this will be accessed as

ClassName instanceName = new ClassName(); 
instanceName.methorOrAttributeNameGoesHere

For class associated attribute aka Static attribute can be direcly accessed as ClassName.methorOrAttributeNameGoesHere

These are very basics of Java and probably you should first read some good book on Java and OOP like 'Head First Java'

The simple answer to this is that instantiation like new BufferedReader() always creates a different instance each time you call it; invoking a method like System.console() might or might not give you different instance.

Ultimately, all objects are instantiated via new ; you just might not see it in your code.

Here are a couple of ways in which System.console() might be implemented (totally simplified, not actually like it is):

// (1) Returns new instance each time
class System {
  static Console console() {
    return new Console();
  }
}

or

// (2) Returns same instance each time
class System {
  private static final Console CONSOLE = new Console();

  static Console console() {
    return CONSOLE;
  }
}

(There are infinitely more ways to implement it, these are just two examples. You can see the way it is implemented in OpenJDK by looking at the source code - it is similar to (2), in that the same instance is returned each time, just with a few more complications that I don't want to describe here)

In (1), if you invoke System.console() twice, you will get back two different instances of Console :

System.console() != System.console()

In (2), if you invoke System.console() twice, you will get back the same instance of Console :

System.console() == System.console()

The question I would ask here is do I need to care if I get back different instances or the same instance? The answer is probably not , if the API designer has done a reasonable job.

The decision as to whether expose the creation of a new Console was made by the person who wrote the classes. There are a number of reasons why he/she might not want you to create a different instance each time you invoke that method, eg:

  • The thing you are creating might be very expensive (slow, takes up lots of resources etc), so you don't want to create lots of them;
  • The thing you want has logically just one instance (it is a singleton).

There are a number of reasons why he/she might want you to create a separate instance each time you invoke that method, eg:

  • You don't want all of the places using that instance to share state. You have to worry about things like thread safety when instances of mutable classes are shared.

And there are a number of reasons why you might not want the user to invoke the constructor directly:

  • new Console() creates an instance of Console exactly ; things like consoles are often platform-dependent, so you might actually want an instance of WindowsConsole , MacConsole etc to be returned when run on Windows, MacOS etc. If WindowsConsole and MacConsole extend Console , either of these can be returned from the System.console() method.
  • Prior to the introduction of the diamond operator <> in Java 7, it was necessary to include the full generic parameters in the new statement, eg ArrayList<HashMap<String, List<String>>> list = new ArrayList<HashMap<String, List<String>>>(); ; however, generic methods allowed this to be written as ArrayList<HashMap<String, List<String>>> list = newList() :

     <T> List<T> newList() { return new ArrayList<T>(); } 
  • (Sometimes, you need a lot of parameters to pass to the constructor, and it is convenient to use the Builder Pattern . This isn't relevant to the cases in the question, but it is a reason for not invoking the constructor directly.)

The thing is that these are internal implementation details, and should be encapsulated : you, as a user of the Console class, shouldn't need to care about how expensive it is to create, or whether there is shared state: you just want a Console .

This encapsulation is effected by providing a method like System.console() : you don't need to know whether the method is implemented like (1) or (2) above (or any other method).

Additionally, if the class is originally written like (1), and that proves to be problematic, its implementation can be changed to (2) without you, as a user of the System class, needing to update your code.

This might be a bit too much detail for a beginner, and I can try to help you understand more; the long and short of it is that sometimes it is be better if you don't create instances directly.

System.console,console is static thats why we are calling it with class name directly,and to call the non static method we generally used the objectname.methodname .

The java.io.Console class is attached with system console internally.System class provides a static method console() that returns the unique instance of Console class.Thats why we used to do as Console c = system.console() ;

Please read about Static classes and non static classes method invocation/instance creation for more details.

Static methods don't require an instance, but non-static methods do. System.console() is static, but new BufferedReader(...).read(...) is not

Static methods are typically used when the outcome of the method will never change based on the context. For instance:

Math.abs(-3); //will always be 3, no matter what

However consider this class:

public class Person {
  private String name;

  public Person(String name){
      this.name = name;
  }

  public String getName() { 
    return name;
  }

  /*
   * In this world, no special characters are allowed in a person's name
   */
  public static boolean isValidName(String name) {
     if (name.contains("!#$%&(=?") {
        return false;
     }
     return true;
  }

}


Person mySister = new Person("Mary");
Person myBrother = new Person("David");

Calling Person.getName() doesn't make any sense; this is like asking "What is a person's name?" without specifying who the person is. Now if you ask me "What is your sister's name?", then I can call mySister.getName() and give you a sensible answer.


Re: your comment "how do you know when to not use new"

If you are trying to create a new Person object (imagine you just had a baby), but you are wondering whether or not that amazing name you found on the internet will be accepted by the authorities:

boolean validName1 = Person.isValidName("LordVoldeMort!!!!!"); //returns false
boolean validName2 = Person.isValidName("HarryPotter2016"); //returns true

Person myLittleBabySon = new Person("HarryPotter2016"); //Accepted by authorities

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM