如何在Processing静态类中实例化Datum对象且不创建主类实例?
问题背景
我正在用Java编写Processing 4程序,主类GeometryView继承自PApplet,代码如下:
ArrayList<Datum> datums = new ArrayList<Datum>(); void setup(){ size(1400, 900); surface.setResizable(true); //fullScreen(); frameRate(120); datums.add(new Datum(0,0)); datums.add(new Datum(1,2)); datums.add(new Datum(3,4)); } void draw() { background(30); stroke(220); if(Functions.convex(datums.get(0),datums.get(1),datums.get(2))){ println("These points are part of a convex corner of geometry"); } }
用于存储坐标的Datum类在单独标签页:
class Datum { float x; float y; Datum(float x, float y){ this.x = x; this.y = y; } void drawDatum(int size){ //print("X = " + this.x + ", Y = " + this.y); ellipse(this.x, -this.y, size, size); } Datum clone(){ return new Datum(x,y); } }
静态工具类Functions中调用new Datum(x,y)时出现错误:
No enclosing instance of type GeometryView is accessible. Must qualify the allocation with an enclosing instance of type GeometryView.
若将Datum设为静态,drawDatum方法调用ellipse时又报错:
Cannot make a static reference to the non-static method ellipse(float, float, float, float) from the type PApplet
不想通过实例化整个主类解决问题,询问如何在Functions中使用new Datum(x,y)且不破坏现有程序,以及创建主类引用是否会引发内存问题。
错误原因分析
- 第一个错误:
Datum是非静态内部类,默认持有外部类GeometryView的引用,静态类Functions没有外部类实例,无法直接创建非静态内部类的对象。 - 第二个错误:
ellipse是PApplet的非静态方法,静态类Datum无法直接调用非静态成员,必须通过PApplet实例访问。
解决方案
方案1:将Datum改为静态内部类,并修改drawDatum方法
把Datum声明为静态内部类,同时让drawDatum接收PApplet实例作为参数,通过该实例调用ellipse:
static class Datum { float x; float y; Datum(float x, float y){ this.x = x; this.y = y; } void drawDatum(PApplet app, int size){ app.ellipse(this.x, -this.y, size, size); } Datum clone(){ return new Datum(x,y); } }
在主类中调用drawDatum时传入this(主类本身就是PApplet实例):
datums.get(0).drawDatum(this, 10);
这样Functions类中可以直接new Datum(x,y),因为静态内部类不需要外部类实例。
方案2:将Datum改为顶级类
把Datum移到单独的.java文件中(成为顶级类),这样它不属于任何内部类,静态类Functions可以直接创建Datum对象。同时修改drawDatum方法,同样接收PApplet实例:
// Datum.java文件 public class Datum { float x; float y; public Datum(float x, float y){ this.x = x; this.y = y; } public void drawDatum(PApplet app, int size){ app.ellipse(this.x, -this.y, size, size); } public Datum clone(){ return new Datum(x,y); } }
主类调用方式和方案1一致,这种方式结构更清晰,适合工具类的复用。
关于主类引用的内存疑问
如果只是在Functions中持有主类GeometryView的引用,不会引发内存问题——因为主类本身就是程序运行的核心实例,只要没有循环引用(比如GeometryView又持有Functions的静态引用且无法释放),就不会有内存泄漏。但相比之下,上面的两种方案不需要额外持有主类引用,代码更简洁优雅,更推荐使用。
内容的提问来源于stack exchange,提问作者Andrew Cline

