为了账号安全,请及时绑定邮箱和手机立即绑定

用Java模拟指针?在科特林?

用Java模拟指针?在科特林?

斯蒂芬大帝 2022-07-06 18:51:25
我正在尝试模拟另一种晦涩的编程范例中使用的一种指针,因此我可以将一些代码移植到 Java。另一种语言不是面向对象的,而是受到 Pascal 的粗略启发。在原始语言中,我们可以编写这样的代码。首先,使用文本。// Start with text.Text myVar = "Bonjour" Pointer myPointer = ->myVar       // Referencing a string variable, storing the reference in another variable of type `Pointer`.Message( myPointer-> )    // Dereferencing the pointer, to retrieve `myVar`, and pass the string to a command `Display` that displays the message on screen in a dialog box.然后,切换到数字。// Switch gears, to work with an number.Integer vResult = ( Random % ( vEnd - vStart + 1 ) ) + vStart  // Generate random number.myPointer = ->vResult    // The same pointer now points to numeric variable rather than a textual variable. 我们可以通过变量名的文本来分配一个指针。myPointer = Get pointer( "var" + String($i) ) // Generate pointer variable named `var1`, or `var2`, etc.我们可以向指针询问一个代码号,该代码号表示它所指向的值的数据类型(所指对象的数据类型)。typeCodeNumber = Type( myPointer ) // Returns 11 for an integer, 22 for text.在另一种语言中,编译器确实提供了类型安全。但是当以这种方式使用指针时,我们牺牲了类型安全。编译器会发出警告,指出代码使用在类型方面不明确。我移植此代码的想法是定义一个XPointer类以及为XText和等类型定义的类XInteger。我需要持有对十几种特定已知类型中任何一种的对象的引用,包括对另一个指针的引用。我可以硬编码十几种类型,不需要对所有类型开放。这十几种类型不共享接口或抽象类,除了Object. 即使它们确实共享一个接口/超类,我也不希望它们作为超类返回,而是作为它们原来的具体类返回。当他们进入指针时,他们也应该从指针中出现。我目前的计划是XPointer用一对引用和取消引用方法在 Java 中定义一个类:XPointer::ref( x )在哪里传递, 或class 的对象Dog,甚至是另一个对象。TruckSculptureXPointerXPointer::deref ⇒ x其中 x 是一个被识别为其原始类型的对象,a Dog, aTruck或 aSculpture甚至另一个XPointer对象,而不仅仅是一个Object对象。➥ 有没有办法做这个Java?也许与泛型?➥ 如果在 Java 中不可能,我可以不情愿地切换到 Kotlin。这个指针功能可以在JVM上运行的Kotlin中完成吗?
查看完整描述

3 回答

?
当年话下

TA贡献1890条经验 获得超9个赞

这称为联合变体类型(请参阅C++ 中的Boost.Variant)。后者特别方便,因为它是一组异构类型的类型安全容器,并且最接近您对要移植的代码类型的描述。由于 Java 不支持模板——不,泛型不是模板——你不会得到你正在寻找的东西。

Optional类型是两种类型中最简单的情况:类型 T 和 Null 。鉴于您需要存储的不仅仅是 T 或 Null 类型,它对您不起作用。

您可能想查看JavaSealedUnions。此外,Kotlin 提供了密封类的概念,有助于将值限制为受约束集中的一种类型。


查看完整回答
反对 回复 2022-07-06
?
ITMISS

TA贡献1871条经验 获得超8个赞

这是我能想到的最好的。我认为你不能轻易地制作一个通用类型,而不是它是所有类的父类(如对象)。考虑到类型系统,转换也很困难,您可以通过不允许重新分配不同类型的指针来模仿它,而每次执行获取时只生成一个新指针。如果你不想知道类型本身,你可以在现代 java 中使用 var 来隐藏类型差异。


public class Types {

    public static void main(String[] args) {

        var p = new PascalPointer<>(new PascalInt());

        PascalInt i = p.get();

        var p2 = new PascalPointer<>(i.toPStr()); // mimic generics by type inference.

        PascalString s = p2.get();

        PascalPointer<PascalType> genericPointer = new PascalPointer<>(s);

        genericPointer.set(i);

        var i2 = (PascalInt) genericPointer.get();

    }

    public interface PascalType { }


    public static class PascalInt implements PascalType {

        // cast

        public PascalString toPStr() {

            return new PascalString(); // hide a new to do a conversion instead of a cast really.

        }

    }


    public static class PascalString implements PascalType { }


    public static class PascalPointer<T extends PascalType> {

        T t;

        public PascalPointer(T t) { this.t = t; }

        public T get() { return t;}

        public void set(T t) {this.t = t;}

    }


}

当您想要一个字符串的 Int 视图并更新字符串时,这可能会发生故障(正如我在这里复制的那样)。


查看完整回答
反对 回复 2022-07-06
?
德玛西亚99

TA贡献1770条经验 获得超3个赞

对于冗长的回答,我深表歉意。

我不认为你可以在不失去类型安全的情况下使用泛型实现你想要的。


为了使下一行工作,Java 需要知道Truck该方法返回了一个,defer()以便它可以调用honk()该对象。


p.deref().honk();

但是,如果您使用 Java 泛型,那么这会在编译时推断出类型擦除。

该解决方案意味着添加一个通用类型,例如Pointer<Truck>,但我们不能,因为您希望能够添加十几个特定的已知类型和一个Pointer.


但是......由于您自己编写了这样的行,特别是调用bark()orhonk(),

这意味着您已经知道Pointer引用 aDogorTruck对象。


使用该假设、泛型和对 的修改defer(),您可以非常接近解决方案。


假设我们有这些类,它们没有任何链接。


public class Dog {

    public void bark() {

        System.out.println("Bark ...");

    }

}


public class Truck {

    public void honk() {

        System.out.println("Honk ...");

    }

}

然后我们需要一个像这样的Pointer类,其中deref()方法需要一个Class参数来知道要返回哪个类型。


public class Pointer {


    private Object myObj;


    public <T> void ref(T myObject) {

        this.myObj = myObject;

    }


    public <T> T deref(Class<T> myClazz) {

        try {

            return myClazz.cast(myObj);

        } catch(ClassCastException e) {

            return null;

        }

    }

}

然后您可以执行以下操作


public static void main(String[] args) {

    Pointer pointer = new Pointer();


    Dog dog = new Dog();

    pointer.ref(dog);                  // Reference to a Dog

    pointer.deref(Dog.class).bark();


    Truck truck = new Truck();

    pointer.ref(truck);                // Reference to a Truck

    pointer.deref(Truck.class).honk();


    Pointer subPointer = new Pointer();

    pointer.ref(subPointer);           // Reference to another pointer

    subPointer.ref(truck);             // Other pointer references a Truck

    pointer.deref(Pointer.class).deref(Truck.class).honk();

    subPointer.ref(dog);               // Other pointer references a Dog

    pointer.deref(Pointer.class).deref(Dog.class).bark();


    pointer.ref(null);                 // Clears the reference


    Truck bulldog = new Truck();

    pointer.ref(bulldog);

    pointer.deref(Dog.class).bark();   // Is allowed, but will cause a NullPointerException

}

这将打印出:


Bark ...

Honk ...

Honk ...

Bark ...

在 Pointer.main(Pointer.java:39) 的线程“主”java.lang.NullPointerException 中出现异常


如果您需要将Pointer引用限制为仅对您的十几个特定已知类型和Pointer类本身,那么您需要使用超类(例如Pointerable)扩展它们并相应地修改ref()方法。

然后,您可以防止不扩展此超类的类型被您的指针引用。

例子:

public abstract class Pointerable { }


public class Dog extends Pointerable {

    public void bark() {

        System.out.println("Bark ...");

    }

}


public class Pointer extends Pointerable {


    private Object myObj;


    public <T extends Pointerable> void ref(T myObject) {

        this.myObj = myObject;

    }


    public <T extends Pointerable> T deref(Class<T> myClazz) {

        try {

            return myClazz.cast(myObj);

        } catch(ClassCastException e) {

            return null;

        }

    }


查看完整回答
反对 回复 2022-07-06
  • 3 回答
  • 0 关注
  • 111 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信