【问题标题】:Some classes need initialization and some don't有些类需要初始化,有些则不需要
【发布时间】:2016-01-07 08:41:17
【问题描述】:

我已经尝试搜索“使用新关键字”的答案,但没有找到关于我的具体问题的答案。

为什么有些类必须用关键字new创建而有些则不用

例如:

import java.io.BufferedReader

如果你想使用它,你必须创建一个新实例

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

但例如system.console 也需要import java.io.console。当你想使用它时,你可以输入Console c = system.console()

我是 Java 和 OO 编程的初学者,在我的书中找到了几个这样的例子。

感谢帮助

【问题讨论】:

  • 尝试阅读静态类
  • Console是System类的静态方法,所以实际上调用了Console构造函数(new Console(something)),只是你看不到而已。

标签: java class keyword


【解决方案1】:

在 java 中,字段(又名属性)总是与实例或类相关联。

一个类可能有很多实例,要创建实例,您必须使用new 运算符。要访问与实例相关的属性,您需要创建一个,这将被访问为

ClassName instanceName = new ClassName(); 
instanceName.methorOrAttributeNameGoesHere

对于类关联属性又名静态属性可以直接访问为ClassName.methorOrAttributeNameGoesHere

这些是 Java 的基础知识,您可能应该首先阅读一些关于 Java 和 OOP 的好书,例如“Head First Java”

【讨论】:

    【解决方案2】:

    对此的简单回答是,像new BufferedReader() 这样的实例化总是 每次调用它时都会创建一个不同的实例;调用像 System.console() 这样的方法可能会也可能不会给你不同的实例。

    最终,所有对象都通过new 实例化;您可能在代码中看不到它。

    以下是System.console() 可能的几种实现方式(完全简化,实际上并不像它那样):

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

    或

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

    (实现的方法还有无限多,这只是两个例子。你可以通过查看源代码看到way it is implemented in OpenJDK - 它类似于(2),因为每次都返回相同的实例,只是还有一些我不想在这里描述的复杂情况)

    在 (1) 中,如果您调用 System.console() 两次,您将返回两个不同的 Console 实例:

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

    在(2)中,如果你调用System.console()两次,你会得到Console的同一个实例:

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

    我在这里要问的问题是我是否需要关心我返回的是不同的实例还是相同的实例?答案是可能不需要,如果 API 设计者已经完成了合理的工作。

    关于是否公开创建新的Console 的决定是由编写类的人做出的。有很多原因导致他/她可能不希望您在每次调用该方法时创建不同的实例,例如:

    • 您正在创建的东西可能非常昂贵(速度慢、占用大量资源等),因此您不想创建太多;
    • 你想要的东西在逻辑上只有一个实例(它是一个单例)。

    他/她可能希望您在每次调用该方法时创建一个单独的实例的原因有很多,例如:

    • 您不希望使用该实例的所有地方都共享状态。共享可变类的实例时,您必须担心线程安全等问题。

    您可能不希望用户直接调用构造函数的原因有很多:

    • new Console() 创建Console 的实例完全正确;诸如控制台之类的东西通常与平台相关,因此您实际上可能希望在 Windows、MacOS 等上运行时返回WindowsConsole、MacConsole 等实例。如果WindowsConsole 和MacConsole 扩展Console,要么其中可以从System.console() 方法返回。
    • 在 Java 7 中引入菱形运算符 <> 之前,有必要在 new 语句中包含完整的泛型参数,例如ArrayList<HashMap<String, List<String>>> list = new ArrayList<HashMap<String, List<String>>>();;但是,通用方法允许将其写为 ArrayList<HashMap<String, List<String>>> list = newList():

      <T> List<T> newList() { return new ArrayList<T>(); }
      
    • (有时候,你需要很多参数传递给构造函数,使用Builder Pattern很方便。这与问题中的案例无关,但这是一个原因不直接调用构造函数。)

    问题是这些是内部实现细节,应该封装:作为Console 类的用户,你不需要关心创建它的成本有多大,或者是否有共享状态:你只需要一个Console。

    这种封装是通过提供像System.console()这样的方法来实现的:您不需要知道该方法是像上面的(1)还是(2)(或任何其他方法)那样实现的。

    此外,如果该类最初是像 (1) 那样编写的,并且证明是有问题的,那么它的实现可以更改为 (2),而您作为 System 类的用户不需要更新您的代码.

    这对于初学者来说可能有点太详细了,我可以尝试帮助您了解更多;总而言之,有时不直接创建实例会更好。

    【讨论】:

      【解决方案3】:

      System.console,console是静态的,所以我们直接用类名调用它,而调用非静态方法我们一般用objectname.methodname。

      java.io.Console 类在内部附加了系统控制台。系统类提供了一个静态方法console(),它返回了Console 类的唯一实例。这就是为什么我们以前这样做Console c = system.console();

      请阅读有关静态类和非静态类方法调用/实例创建的更多详细信息。

      【讨论】:

        【解决方案4】:

        静态方法不需要实例,但非静态方法需要。 System.console() 是静态的,但new BufferedReader(...).read(...) 不是

        静态方法通常用于方法的结果永远不会根据上下文而改变的情况。例如:

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

        但是考虑这个类:

        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");
        

        调用Person.getName() 没有任何意义;这就像问“一个人的名字是什么?”没有说明这个人是谁。现在如果你问我“你姐姐叫什么名字?”,我可以打电话给mySister.getName(),给你一个明智的答案。


        回复:您的评论“你怎么知道什么时候不使用 new”

        如果您正在尝试创建一个新的 Person 对象(假设您刚生了一个孩子),但您想知道您在互联网上找到的这个惊人的名字是否会被当局接受:

        boolean validName1 = Person.isValidName("LordVoldeMort!!!!!"); //returns false
        boolean validName2 = Person.isValidName("HarryPotter2016"); //returns true
        
        Person myLittleBabySon = new Person("HarryPotter2016"); //Accepted by authorities
        

        【讨论】:

        • 也许这是一个愚蠢的问题......但是如果您忘记了 BufferedReader 之前的“new”关键字,您现在如何将“new”关键字放在“是”或“否”IE 中,它会给出错误。这是通过经验知道哪些是静态方法,哪些不是?或者是否有经验法则可以知道何时需要“新”,何时不需要。感谢大家的帮助
        猜你喜欢
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        • 2021-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多