考虑以下类层次结构.
class ClassA {
private void hello() {
System.out.println("Hello from A");
}
}
interface Myinterface {
default void hello() {
System.out.println("Hello from Interface");
}
}
class ClassB extends ClassA implements Myinterface {
}
public class Test {
public static void main(String[] args) {
ClassB b = new ClassB();
b.hello();
}
}
Run Code Online (Sandbox Code Playgroud)
运行该程序将出现以下错误:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.testing.ClassA.hello()V from class com.testing.Test
at com.testing.Test.main(Test.java:23)
Run Code Online (Sandbox Code Playgroud)
The inherited method ClassA.hello() cannot hide the public abstract method in …我正在寻找一个等同于C#扩展方法功能的java.现在我一直在阅读Java 8的默认方法,但据我所知,我只能将它们添加到接口......
...是否有任何语言功能允许我为没有实现接口的最终类编写扩展方法?(我宁愿不用包装......)
我们来举个例子:
public interface Testerface {
default public String example() {
return "Hello";
}
}
public class Tester implements Testerface {
@Override
public String example() {
return Testerface.super.example() + " world!";
}
}
public class Internet {
public static void main(String[] args) {
System.out.println(new Tester().example());
}
}
Run Code Online (Sandbox Code Playgroud)
简单地说,这将打印出来Hello world!.但是说我正在使用返回值做其他事情Testerface#example,例如初始化数据文件并返回一个不应离开实现类的敏感内部值.为什么Java不允许在默认接口方法上使用访问修饰符?为什么它们不能被保护/私有并且可能被子类提升(类似于扩展父类的类如何为重写方法使用更可见的修饰符)?
一个常见的解决方案是转移到抽象类,但在我的特定情况下,我有一个枚举接口,所以这里不适用.我想它或者被忽略了,或者因为接口背后的原始想法是它们是可用方法的"契约",但我想我想要输入关于这个的内容.
我读过" 为什么"最终"在Java 8接口方法中不允许? ",其中指出:
默认方法的基本思想是:它是具有默认实现的接口方法,派生类可以提供更具体的实现
对我来说听起来就像可见性根本不会破坏那个方面.
与链接的问题一样,因为它看起来很难被关闭,所以在这个问题上会得到权威的答案,而不是基于意见的答案.
假设有两个接口Interface1,Interface2其中Interface2扩展Interface1.
interface Interface1 {
default void method() {
System.out.println("1");
}
// Other methods
}
interface Interface2 extends Interface1 {
@Override
default void method() {
System.out.println("2");
}
// Other methods
}
Run Code Online (Sandbox Code Playgroud)
假设我想创建一个实现的类,Interface2但我想method()成为其中的版本Interface1.如果我写
class MyClass implements Interface1, Interface2 {
public void method() {
Interface1.super.method();
}
}
Run Code Online (Sandbox Code Playgroud)
我收到编译错误:
默认超级调用中的错误类型限定符:冗余接口Interface1由Interface2扩展
可以通过创建第三个界面来解决这个问题:
interface Interface3 extends Interface1 {
default void method() {
Interface1.super.method();
}
}
Run Code Online (Sandbox Code Playgroud)
然后:
class MyClass implements Interface1, Interface2, Interface3 …Run Code Online (Sandbox Code Playgroud) 由于Java 8接口可以有默认方法.我知道如何从实现方法中显式调用该方法,即(请参阅在Java中显式调用默认方法)
但是,如何在代理上使用反射显式调用默认方法?
例:
interface ExampleMixin {
String getText();
default void printInfo(){
System.out.println(getText());
}
}
class Example {
public static void main(String... args) throws Exception {
Object target = new Object();
Map<String, BiFunction<Object, Object[], Object>> behavior = new HashMap<>();
ExampleMixin dynamic =
(ExampleMixin) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{ExampleMixin.class}, (Object proxy, Method method, Object[] arguments) -> {
//custom mixin behavior
if(behavior.containsKey(method.getName())) {
return behavior.get(method.getName()).apply(target, arguments);
//default mixin behavior
} else if (method.isDefault()) {
//this block throws java.lang.IllegalAccessException: no …Run Code Online (Sandbox Code Playgroud) 在开发maven插件时,构建打印错误:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-plugin-plugin:3.3:descriptor (default-descriptor) on project default-method-demo: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.3:descriptor failed: syntax error @[8,1] in file:/full/path/to/project/default-method/src/main/java/org/example/Iface.java -> [Help 1]
Run Code Online (Sandbox Code Playgroud)
即使该文件Iface.java是可编译的.
Iface.java:
package org.example;
public interface Iface {
default String getString() {
return "string";
}
}
Run Code Online (Sandbox Code Playgroud)
从 pom.xml
<packaging>maven-plugin</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)
是什么原因造成的?怎么修好?
我是mockito的忠实粉丝,不幸的是,对于我使用Java 8的一个项目,它失败了...
场景:
public final class MockTest
{
@Test
public void testDefaultMethodsWithMocks()
{
final Foo foo = mock(Foo.class);
//when(foo.bar()).thenCallRealMethod();
assertThat(foo.bar()).isEqualTo(42);
}
@FunctionalInterface
private interface Foo
{
int foo();
default int bar()
{
return 42;
}
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,测试失败并foo.bar()返回0.
当我取消注释该when()行时,我得到一个堆栈跟踪...
java.lang.NoSuchMethodError: java.lang.Object.bar()I
at com.github.fge.lambdas.MockTest.testDefaultMethodsWithMocks(MockTest.java:18)
Run Code Online (Sandbox Code Playgroud)
这是maven上最新的稳定版本; 谷歌搜索周围没有告诉我关于Java 8中这个新功能的模拟状态...
你能否以其他方式使其工作,而不是实现接口和spy()它们(这是有效的)?
我有一个我已经使用了一段时间的自定义界面,看起来像这样:
public interface Function<T, R> {
R call(T input);
}
Run Code Online (Sandbox Code Playgroud)
我想用Java Function和Guava 来改进这个接口Function,同时保持它FunctionalInterface.我以为我有完美的安排:
@FunctionalInterface
public interface Function<T, R> extends
java.util.function.Function<T, R>,
com.google.common.base.Function<T, R> {
R call(T input);
@Override
default R apply(T input) {
return call(input);
}
}
Run Code Online (Sandbox Code Playgroud)
两个超级apply()接口都声明了相同的方法,该方法已在我的界面中实现,只留下抽象call()方法.奇怪的是,它不会编译,告诉我
"@FunctionalInterface"注释无效; 函数<T,R>不是功能接口
更奇怪的是,以下变化编译得很好:
@FunctionalInterface
public interface Function<T, R> extends
java.util.function.Function<T, R> {
R call(T input);
@Override
default R apply(T input) {
return call(input);
}
}
Run Code Online (Sandbox Code Playgroud)
@FunctionalInterface
public interface Function<T, R> extends
com.google.common.base.Function<T, R> …Run Code Online (Sandbox Code Playgroud) 在编写加密实用程序类时,我遇到了以下方法的问题:
public static void destroy(Key key) throws DestroyFailedException {
if(Destroyable.class.isInstance(key)) {
((Destroyable)key).destroy();
}
}
@Test
public void destroySecretKeySpec() {
byte[] rawKey = new byte[32];
new SecureRandom().nextBytes(rawKey);
try {
destroy(new SecretKeySpec(rawKey , "AES"));
} catch(DestroyFailedException e) {
Assert.fail();
}
}
Run Code Online (Sandbox Code Playgroud)
在javax.crypto.spec.SecretKeySpec上述方法的特定情况下可以正常工作,java7因为SecretKeySpec(javadocs 7)没有实现Destroyable(javadocs 7)
现在使用java8类SecretKeySpec(javadocs 8)已经被Destroyable(javadocs 8)和方法Destroyable#destroy现在default哪个很好,根据这个声明
默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性.
然后代码编译没有任何问题,尽管类ScretKeySpec本身没有被更改,单独的接口SecretKey已经.
问题是oracle's jdk8该destroy方法有以下实现:
public …Run Code Online (Sandbox Code Playgroud) 请考虑以下界面:
public interface I {
default String getProperty() {
return "...";
}
}
Run Code Online (Sandbox Code Playgroud)
和刚刚重用默认实现的实现类:
public final class C implements I {
// empty
}
Run Code Online (Sandbox Code Playgroud)
每当C在JSP EL脚本上下文中使用实例时:
<jsp:useBean id = "c" class = "com.example.C" scope = "request"/>
${c.property}
Run Code Online (Sandbox Code Playgroud)
- 我收到了PropertyNotFoundException:
javax.el.PropertyNotFoundException: Property 'property' not found on type com.example.C
javax.el.BeanELResolver$BeanProperties.get(BeanELResolver.java:268)
javax.el.BeanELResolver$BeanProperties.access$300(BeanELResolver.java:221)
javax.el.BeanELResolver.property(BeanELResolver.java:355)
javax.el.BeanELResolver.getValue(BeanELResolver.java:95)
org.apache.jasper.el.JasperELResolver.getValue(JasperELResolver.java:110)
org.apache.el.parser.AstValue.getValue(AstValue.java:169)
org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:184)
org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:943)
org.apache.jsp.index_jsp._jspService(index_jsp.java:225)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Run Code Online (Sandbox Code Playgroud)
我最初的想法Tomcat 6.0对于Java 1.8功能来说太旧了,但我很惊讶Tomcat 8.0也受到了影响.当然,我可以通过显式调用默认实现来解决这个问题:
@Override
public String getProperty() {
return I.super.getProperty();
}
Run Code Online (Sandbox Code Playgroud)
- …
default-method ×10
java ×9
java-8 ×9
el ×1
jsp ×1
lambda ×1
maven ×1
maven-plugin ×1
mockito ×1
reflection ×1
secret-key ×1