Kotlin:'public'函式公开其'private-in-class'传回型别参数Point

jv4diomz  于 2022-11-16  发布在  Kotlin
关注(0)|答案(1)|浏览(179)

编辑:我在结尾提供了解决问题的JAVA代码。

我想知道如何在Kotlin中创建一个私有嵌套类,以便可以从它的父类访问它,但不能从其他任何地方访问它。
在下面的代码片段中,我用“//(!)"标记了发生编译错误的行。

class Sphere(val radius: Double = 1.toDouble()) {
    
        var pointsLinkedHashSet: LinkedHashSet<Point> = linkedSetOf() 
        //(!)'public' property exposes its 'private-in-class' type argument Point (make "Point" public)
    
        fun getPoints(): LinkedHashSet<Point> {
            return pointsLinkedHashSet
        } 
        //(!) 'public' function exposes its 'private-in-class' return type argument Point (make "Point" public)
    
        fun getLastPoint(): Point = pointsLinkedHashSet.last()
        //(!) Same as previous

        fun clearPoints() = pointsLinkedHashSet.clear()
    
        fun addPoint(radius: Double = this.radius, latitude: Double, longitude: Double): Point {
            val point = Point(radius, latitude, longitude)
            pointsLinkedHashSet.add(point)
            return point
        }
        //(!) Same as previous
    
        private class Point(
            val radius: Double,
            val latitude: Double,
            val longitude: Double
        )
    
    }

换句话说,这是我的Main类:

class Main {

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val sphere = Sphere()
            val point = sphere.addPoint(10.toDouble(), 10.toDouble(), 10.toDouble()) //this works as it should
            val point1 = sphere.getLastPoint() // this too
            val point2 = Sphere.Point(10.toDouble(), 10.toDouble(), 10.toDouble()) //this doesn't work because Point is private, as it should
            val radius = point.radius //same in these next 3 lines
            val latitude = point.latitude
            val longitude = point.longitude 
        }
    }
}

我已经在代码注解中描述了所需的行为。
这在Java中很容易实现,但在Kotlin中我还找不到一种方法来实现它,而且找不到任何与这个问题相关的文章,尽管它很容易遇到。
还是我漏掉了什么明显的东西?你能帮忙吗?谢谢。

使用JAVA代码更新:

球体类:

package org.example;
import java.util.LinkedHashSet;
public class Sphere {
    private final Double radius;
    private final LinkedHashSet<Point> pointsLinkedHashSet = new LinkedHashSet<Point>();
    public Double getRadius() {
        return this.radius;
    }
    public Sphere(Double radius) {
        this.radius = radius;
    }
    public Point getLastPoint() {
        if (pointsLinkedHashSet.isEmpty()) return null;
        return (Point) pointsLinkedHashSet.toArray()[pointsLinkedHashSet.size() - 1];
    }
    public Point addPoint(Double latitude, Double longitude) {
        Point point = new Point(latitude, longitude);
        pointsLinkedHashSet.add(point);
        return point;
    }
    class Point {
        private final Double radius;
        private final Double latitude;
        private final Double longitude;
        Double getLatitude() {
            return latitude;
        }
        Double getLongitude() {
            return longitude;
        }
        Double getRadius() {
            return this.radius;
        }
        private Point(Double latitude, Double longitude) {
            this.radius = Sphere.this.radius;
            this.latitude = latitude;
            this.longitude = longitude;
        }
    }
}

主类:

package org.example;

public class Main {
    public static void main(String[] args) {
        Sphere sphere = new Sphere(1.0);
        System.out.println("Sphere radius = " + sphere.getRadius());
        Sphere.Point point = sphere.addPoint(10.0,10.0);
        System.out.println("Point radius = " + point.getRadius());
        System.out.println("Point latitude = " + point.getLatitude());
        System.out.println("Point longitude = " + point.getLongitude());
//        Sphere.Point point = new Sphere.Point(10.0,10.0); does not work
//        can not create new Point object because its constructor is private,
//        this is desired behaviour!
        Sphere.Point point1 = sphere.getLastPoint();
        System.out.println("Point1 radius = " + point1.getRadius());
        System.out.println("Point1 latitude = " + point1.getLatitude());
        System.out.println("Point1 longitude = " + point1.getLongitude());
    }
}

输出量:

Sphere radius = 1.0
Point radius = 1.0
Point latitude = 10.0
Point longitude = 10.0
Point1 radius = 1.0
Point1 latitude = 10.0
Point1 longitude = 10.0
1rhkuytd

1rhkuytd1#

令人困惑的是,你的请求根本就不是一个私有类。私有类是一个完全不能从文件外部访问的类,所以从文件中的任何公共函数返回它作为一个类型是没有意义的。Java中也是如此。
你的Java代码并没有把Point私有化,它只是把它的构造函数私有化,所以我猜你真正想要的是防止Point类从这个文件之外示例化。
在Kotlin中似乎没有一种方法可以复制这种行为。(Discussion here)最接近的方法是将构造函数标记为internal
或者,将类标记为inner就足够了,这样类就不能在没有外部类的上下文的情况下示例化。可以调用someSphereInstance.Point(...),但不能调用Sphere.Point(...)
注意,将嵌套类设为inner会使它更像Java代码。这两种类型的嵌套类在Java和Kotlin中的声明是不同的:

嵌套类的修饰符关键字:

| | 绑定到外部类示例|独立于外部示例|
| - -|- -|- -|
|** java *| 无 *| static|
| "Kotlin"| inner| * 无 *|

相关问题