创建一个无法创建对象的类

10

我正在攻读本科学位,我的教授给了我一个任务,他说:创建一个没有使用任何访问修饰符或接口关键字的类,该类的对象无法被创建。

我在谷歌上查找,但找不到解决方案。这个问题如何在Java中实现?


教授没有给你更多的信息来工作吗?定义“无法创建”。 - T.J. Crowder
13
我是BS专业的学生。虽然英语可能不是你的母语,但你可能知道这句话有一个非常有趣的解释:“我是一名bullsh*t(废话)的学生”。 - Andy Turner
1
构造函数可以抛出异常。 - JonK
1
枚举类型算作类吗?enum Foo {} - Andy Turner
1
创建一个带有语法错误的类算作作弊吗?:-P 同样,您还可以创建一个具有静态实例成员的类,该成员本身无法实例化(导致编译时错误,尽管在语法上是正确的),或者使其构造函数调用不存在的方法。请不要太认真对待这个问题。 - The Vee
显示剩余2条评论
5个回答

12

枚举是类(JLS§8.9),不能实例化和子类化;只需创建一个没有任何值的枚举:

enum Foo {}

其他可能性根据不同的解释而异:

JonKT.J. Crowder 考虑从构造函数中抛出异常:

final class Example {
    Example() {
        throw new Exception();
    }
}

但是 nick zoum 指出,一个实例在异常之前仍然会被创建并存在于系统中,即使在上面的例子中无法保留该实例。

nick zoum 考虑使用 abstract

abstract class Example {
}

... 但是T.J. Crowder 指出,abstract类可以被子类继承(它们不能是 final), 而一个子类实例"是一个"超类实例。


我认为这是唯一真正实现它的解决方案。JLS将枚举称为“特殊类类型”,因此它们是类。但是您无法对它们进行子类化,也无法使用new与它们,并且唯一的实例是它们的值。因此,没有值的枚举是一个无法实例化的类(除非可能通过操作字节码,我认为任何合理的人都会同意这是超出界限的)。 - T.J. Crowder
1
@AndyTurner 按照TJCrowder的指示,随意将我的答案添加到你的答案中。 - nick zoum
@nickzoum:已完成。 :-) - T.J. Crowder
1
我认为在构造函数中抛出异常更可能是预期的答案。实例短暂存在是一个有趣的副作用,但对于使用代码的人来说并不真正相关。 - IMSoP
从技术上讲,可以使用反射仍然创建枚举类。 - Ferrybig
@FerryBig 不是真的。正如在语言规范中所述,“禁止枚举类型的反射实例化”。 - Andy Turner

6

我不擅长Java,但是其他答案给了我这个想法:

import java.util.*;
import java.lang.*;
import java.io.*;


class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Object o = new Problematic();

        // unreachable

    }
}

class Problematic
{
    static 
    {
        int i = 1 / 0 ;
    }
}

在ideone上试一试

我相信没有办法使一个叫做Problematic的东西能够幸存...

(注意,当我在静态初始化程序中尝试使用throw new Exception();时,它无法编译)


1
基本上是“从构造函数中抛出异常”的变体想法,但是在类级别而不是实例级别。确实,如果您无法初始化类,则无法创建实例+1 - Hulk
1
throw new RuntimeException(); 应该在静态初始化程序中起作用。 - kapex
1
@Kapep 也会得到 "Main.java:20: error: initializer must be able to complete normally" 的错误,就像 Exception 一样。 - AakashM
1
不错,我不知道静态初始化程序不能总是抛出异常甚至使用“return”。我刚刚尝试了“if (true) throw new RuntimeException();”,这很好用,所以检查似乎不太严格。 - kapex

3

您尝试使用了 abstract 关键字吗?

例如:

abstract class Test{}

当然,这可以被覆盖,所以请查看此答案以获取更可靠的设计。

2
我可以通过子类创建其中之一。请记住,即使是子类实例也“是”Test - T.J. Crowder
3
@TheresaForster,是的,试试看! - Andy Turner
1
@TheresaForster:一个final abstract类将无法编译。 - T.J. Crowder
3
是的,它是的。这句话的意思是一个子类确实属于Test的实例。 - T.J. Crowder
1
@TheresaForster new Test() {} instanceof Test 是正确的。使用 abstract 并不是这个问题的有效答案。 - Andy Turner
显示剩余9条评论

0

匿名内部类应该是答案。

示例:

public abstract class HelloWorld{
    abstract void x();
    public static void main(String []args){
        System.out.println("Hello World"); 
        HelloWorld h = new HelloWorld(){
            void x(){
                System.out.println(" ");
            }
        }; 
        h.x(); 
    } 
}

创建了一个类,但它的名称由编译器决定,该类继承了HelloWorld类,并提供了x()方法的实现。

2
为了使这个回答有用,你应该展示一些能够实现此功能的代码。 - hyde
公共抽象类 HelloWorld { 抽象 void x(); public static void main(String[] args) { System.out.println("Hello World"); HelloWorld h = new HelloWorld() {void x() {System.out.println(" ");}}; h.x(); } } - RAHUL ROY
这里创建了一个类,但它的名称由编译器决定,该类扩展了HelloWorld类并提供了x()方法的实现。 - RAHUL ROY

0

没有听到您的教授具体说法,"不使用任何访问修饰符"可能意味着他们试图教您如何使用"默认"访问修饰符?

如果是这样的话:

package mypackage.nocreate;
class MyClass {
}

然后:

package mypackage;
import mypackage.nocreate.MyClass;

public class Test {
    public static void main(String[] args) {
        new MyClass();   // not allowed - in a different package
    }
}

你可以认为 - 至少在源代码中 - 它不使用任何访问修饰符 :)

我认为"acces-modifer"限制是为了防止在final类上使用私有构造函数。 - Asoub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接