【问题标题】:How do I get object and not address without using String/ toString?如何在不使用 String/toString 的情况下获取对象而不是地址?
【发布时间】:2018-10-27 09:29:55
【问题描述】:

我需要创建自己的 String 类,称为 MyString,而不使用默认的 String 类/向量 API。我必须处理一些必需的方法,它们的返回类型是预先确定的。只要不使用String,我可以添加其他方法。

预期用途是:

(在 main)System.out.println(str.toLowerCase()) - 返回 str 的小写

当我想使用返回类型为MyStringtoLowerCase() 方法时,我无法返回对象内容而只能返回地址。

通常,这个问题需要修改toString(),但是由于这个方法默认需要返回类型为String,所以我不能使用修改toString()进行赋值。

作业应该不那么难,不需要复杂的扩展。我的构造函数可能是问题所在,但我无法指定是哪一部分。

代码

public class MyString {
private char value[];

MyString(char[] arr){
    this.value = Arrays.copyOf(arr, arr.length);
}

... 

MyString toLowerCase() { // can't change return type
    for (int i =0; i<value.length; i++) {
        if ((int)value[i] > 64 && (int)value[i] < 91) {
            value[i] = (char) (value[i]+32);
        }
    }
    return this; // this returns address, and I can't override toString
}

【问题讨论】:

  • 与内部 Java 类交互的唯一方法是通过指定的 API - toString 是该 API 的一部分。 没有其他方式可以描述您希望如何将您的课程打印为String。您可以考虑添加一个PrintWriter 装饰器 - 一个MyStringPrintWriter,它使用某种方法获取MyString 并将其输出到char by char
  • @aka-one 为什么? MyString 可以是可变的。 String 不可变不会影响自定义实现。
  • @aka-one 不确定我理解你的意思。类的可变性或不变性会影响它的共享方式。这不影响需要实现哪些方法,只影响它们的如何实现。如果你想编写自己的字符串类,你将不得不重新实现所有方法。

标签: java string overriding tostring


【解决方案1】:

System.out.println(str.toLowerCase()) 的问题是它最终调用了PrintStream.println(Object o),但是该方法在某些时候在内部调用了o.toString(),它使用从Object#toString() 继承的代码(因为你不能像预期的那样覆盖toString结果String,这在您的项目中是被禁止的),结果是表单TypeInfo@hexHashCode

这意味着你不能使用System.out.println(MyString)

但是PrintStream(该实例由System.out 持有)允许我们提供以不同形式打印的数据。在这种情况下,您可以使用println(char[])。您需要做的就是添加到MyString 方法,例如toCharArray(),它将返回(最好是副本)MyString 类持有的字符数组。

这样您就可以像 System.out.println(myStringInstance.toCharArray()) 一样使用它,所以您的 main 方法中的代码需要看起来像

System.out.println(str.toLowerCase().toCharArray());
//                                   ^^^^^^^^^^^--this should return char[]

【讨论】:

    【解决方案2】:

    首先,String 类是不可变类型,即String 的方法不会改变内部状态(即char 数组),而是返回String 类型的新实例。 要反映这种行为,您可以实现如下内容:

    public MyString toLowerCase() {
        char temp = new char[value.length];
        // [...] Your code performing the actual logic on temp
        return new MyString(temp);
    }
    

    String 类的不变性(及其含义)在实践中非常重要。例如,以下代码会产生预期的结果:

    String word = "Word";
    System.out.println("I can produce upper case (" + word.toUpperCase() + ") " + 
                       "and lower case (" + word.toLowerCase() + ") " + 
                       "without any side-effects on the original (" + word + ").");
    

    但是,不可能(没有“hacky”解决方案)实现这样的方法:

    void shortenString(String inputAndOutput);
    

    其次,作业期望类/方法必须使用如下:

    System.out.println(str.toLowerCase());
    

    out 属性实际上是一个PrintStream,它提供(除了其他方法之外)以下两个:

    println(Object x) - 打印一个对象然后终止该行。

    println(String x) - 打印一个字符串然后终止该行。

    如果使用Object 参数调用该方法,则内部实现在给定对象上调用toString(),因此满足要求的唯一方法是覆盖该方法。不幸的是,这项任务不允许这样做。

    但是,如果没有明确说明解决方案必须使用java.lang.System,您可以简单地实现自己的接受MyStringSystem 类,例如:

    public class System {
        public static class MyPrintStream /* optional: extends PrintStream */ {
             public void println(MyString x) {
                 java.lang.System.out.println(x.getCharArray());
             }
        }
    
        public static final out = new MyPrintStream();
    }
    

    这将允许您完全按照作业中的描述使用它:

    import my.package.System;
    
    public class Main {
        public static void main(String[] args) {
            // [...] Instantiate str
            System.out.println(str.toLowerCase());
        }
    }
    

    【讨论】:

    • 虽然String 是不可变的,但没有暗示他自己的MyString 类也必须是不可变的。
    • 我认为本次作业的主要目的是理解String 类的概念和内部结构,其中一个非常重要的概念是不变性。
    猜你喜欢
    • 2015-03-26
    • 2023-03-25
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 2022-12-20
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多