事情的起因,在看spring源码的时候,经常能看到一个内部类,而且,内部类用static关键字修饰。如
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@Conditional(SpringBootAdminClientEnabledCondition.class)
@AutoConfigureAfter({ WebEndpointAutoConfiguration.class, RestTemplateAutoConfiguration.class,
WebClientAutoConfiguration.class })
@EnableConfigurationProperties({ ClientProperties.class, InstanceProperties.class, ServerProperties.class,
ManagementServerProperties.class })
public class SpringBootAdminClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public StartupDateMetadataContributor startupDateMetadataContributor() {
return new StartupDateMetadataContributor();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public static class ServletConfiguration {
@Bean
@Lazy(false)
@ConditionalOnMissingBean
public ApplicationFactory applicationFactory(InstanceProperties instance, ManagementServerProperties management,
ServerProperties server, ServletContext servletContext, PathMappedEndpoints pathMappedEndpoints,
WebEndpointProperties webEndpoint, ObjectProvider<List<MetadataContributor>> metadataContributors,
DispatcherServletPath dispatcherServletPath) {
return new ServletApplicationFactory(instance, management, server, servletContext, pathMappedEndpoints,
webEndpoint,
new CompositeMetadataContributor(metadataContributors.getIfAvailable(Collections::emptyList)),
dispatcherServletPath);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.REACTIVE)
public static class ReactiveConfiguration {
@Bean
@Lazy(false)
@ConditionalOnMissingBean
public ApplicationFactory applicationFactory(InstanceProperties instance, ManagementServerProperties management,
ServerProperties server, PathMappedEndpoints pathMappedEndpoints, WebEndpointProperties webEndpoint,
ObjectProvider<List<MetadataContributor>> metadataContributors) {
return new DefaultApplicationFactory(instance, management, server, pathMappedEndpoints, webEndpoint,
new CompositeMetadataContributor(metadataContributors.getIfAvailable(Collections::emptyList)));
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(RestTemplateBuilder.class)
public static class BlockingRegistrationClientConfig {
@Bean
@ConditionalOnMissingBean
public BlockingRegistrationClient registrationClient(ClientProperties client) {
RestTemplateBuilder builder = new RestTemplateBuilder().setConnectTimeout(client.getConnectTimeout())
.setReadTimeout(client.getReadTimeout());
if (client.getUsername() != null && client.getPassword() != null) {
builder = builder.basicAuthentication(client.getUsername(), client.getPassword());
}
return new BlockingRegistrationClient(builder.build());
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(WebClient.Builder.class)
@ConditionalOnMissingBean(RestTemplateBuilder.class)
public static class ReactiveRegistrationClientConfig {
@Bean
@ConditionalOnMissingBean
public ReactiveRegistrationClient registrationClient(ClientProperties client, WebClient.Builder webClient) {
if (client.getUsername() != null && client.getPassword() != null) {
webClient = webClient.filter(basicAuthentication(client.getUsername(), client.getPassword()));
}
return new ReactiveRegistrationClient(webClient.build(), client.getReadTimeout());
}
}
}
为什么要这么写???带着疑问,做了下测试。
package org.test.dog;
public class Dog {
class A {
private String p;
public String getP() {
return p;
}
public void setP(String p) {
this.p = p;
}
}
static class B {
private String p;
public String getP() {
return p;
}
public void setP(String p) {
this.p = p;
}
}
public class C {
private String p;
public String getP() {
return p;
}
public void setP(String p) {
this.p = p;
}
}
public static class D {
private String p;
public String getP() {
return p;
}
public void setP(String p) {
this.p = p;
}
}
A a = new A();
B b = new B();
C c = new C();
D d = new D();
}
测试的重点,分为两种,一是和 Dog同处一个包里的 InnerPackageTest,目的是为了测试Dog.A, Dog.B,因为它们没有使用public关键字。二是和Dog没有处在同一个包的里的 OutPackageTest。
内部测试类
package org.test.dog;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 演示了内部测试(InnerPackageTest和Dog所处同一个包)。
*
* @author cpp
*
*/
public class InnerPackageTest {
private static Integer newLine = 2;
public static void main(String[] args) throws Exception, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException {
Dog a = new Dog();
System.out.println("----------------- A测试开始");
// new Dog.A(); //报错,编译不通过
Dog.A a1 = a.new A();
message("打印实例:", a1);
message("构造器个数:", Dog.A.class.getConstructors().length);
newLIne(newLine);
System.out.println("----------------- B测试开始");
//
Dog.B b = new Dog.B();
b.setP("");
message("构造器个数:", Dog.B.class.getConstructors().length);
message("打印实例:", b);
newLIne(newLine);
System.out.println("----------------- C测试开始");
//
Dog.C c = a.new C();
message("打印实例:", c);
// new Dog.C();// 报错
message("构造器个数:", Dog.C.class.getConstructors().length);
Constructor[] cs = Dog.C.class.getConstructors();
for (int i = 0; i < cs.length; i++) {
message("构造器的样子:", cs[i].toGenericString());
}
Object c2 = Dog.C.class.getConstructors()[0].newInstance(a);
message("反射出来的对象", c2.toString());
newLIne(newLine);
System.out.println("----------------- D测试开始");
Dog.D d = new Dog.D();
message("打印实例:", d);
message("构造器个数:", Dog.D.class.getConstructors().length);
cs = Dog.D.class.getConstructors();
for (int i = 0; i < cs.length; i++) {
message("构造器的样子:", cs[i].toGenericString());
}
Object d2 = Dog.D.class.getConstructors()[0].newInstance();
message("反射出来的对象", d2.toString());
}
public static void message(Object... args) {
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + "\t");
}
System.out.println();
}
public static void newLIne(int newLIne) {
for (int i = 1; i <= newLIne; i++) {
System.out.println();
}
}
}
输出的结果为
----------------- A测试开始
打印实例: org.test.dog.Dog$A@61f8bee4
构造器个数: 0
----------------- B测试开始
构造器个数: 0
打印实例: org.test.dog.Dog$B@7b49cea0
----------------- C测试开始
打印实例: org.test.dog.Dog$C@887af79
构造器个数: 1
构造器的样子: public org.test.dog.Dog$C(org.test.dog.Dog)
反射出来的对象 org.test.dog.Dog$C@7fac631b
----------------- D测试开始
打印实例: org.test.dog.Dog$D@5b87ed94
构造器个数: 1
构造器的样子: public org.test.dog.Dog$D()
反射出来的对象 org.test.dog.Dog$D@6e0e048a
外部测试类
package org.test.cat;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.test.dog.Dog;
/**
* 演示了外部测试(OutPackageTest和Dog,没有在同一个包内)。
*
* @author cpp
*
*/
public class OutPackageTest {
private static Integer newLine = 2;
public static void main(String[] args) throws Exception, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException {
Dog a = new Dog();
System.out.println("----------------- A测试开始");
// new Dog.A(); //报错,编译不通过
// Dog.A a1 = a.new A();// 报错,编译不通过
// message("打印实例:", a1);
// message("构造器个数:", Dog.A.class.getConstructors().length);
newLIne(newLine);
System.out.println("----------------- B测试开始");
//
// Dog.B b = new Dog.B(); //报错,编译不通过
// b.setP("");
// message("构造器个数:", Dog.B.class.getConstructors().length);
// message("打印实例:", b);
newLIne(newLine);
System.out.println("----------------- C测试开始");
//
Dog.C c = a.new C();
message("打印实例:", c);
// new Dog.C();// 报错
message("构造器个数:", Dog.C.class.getConstructors().length);
Constructor[] cs = Dog.C.class.getConstructors();
for (int i = 0; i < cs.length; i++) {
message("构造器的样子:", cs[i].toGenericString());
}
Object c2 = Dog.C.class.getConstructors()[0].newInstance(a);
message("反射出来的对象", c2.toString());
newLIne(newLine);
System.out.println("----------------- D测试开始");
Dog.D d = new Dog.D();
message("打印实例:", d);
message("构造器个数:", Dog.D.class.getConstructors().length);
cs = Dog.D.class.getConstructors();
for (int i = 0; i < cs.length; i++) {
message("构造器的样子:", cs[i].toGenericString());
}
Object d2 = Dog.D.class.getConstructors()[0].newInstance();
message("反射出来的对象", d2.toString());
}
public static void message(Object... args) {
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + "\t");
}
System.out.println();
}
public static void newLIne(int newLIne) {
for (int i = 1; i <= newLIne; i++) {
System.out.println();
}
}
}
输出的结果为
----------------- A测试开始
----------------- B测试开始
----------------- C测试开始
打印实例: org.test.dog.Dog$C@61f8bee4
构造器个数: 1
构造器的样子: public org.test.dog.Dog$C(org.test.dog.Dog)
反射出来的对象 org.test.dog.Dog$C@7b49cea0
----------------- D测试开始
打印实例: org.test.dog.Dog$D@887af79
构造器个数: 1
构造器的样子: public org.test.dog.Dog$D()
反射出来的对象 org.test.dog.Dog$D@7fac631b
总结一下,学习到的内容。
1、内部类A,B,由于没有使用修饰符,则默认的范围为包级别,这一点不变。
2、内部类A,B,在同一个包里被引用的时候,不能直接new,而是要通过Dog的实例对象来new。通过获取到的构造器个数来看,数量为0,也证实了这一点。
3、内部类C,如果只加了public,而不是public static时,根据获取的造造器来看,是有一个Dog参数的,所以,内部类C,虽然有public关键字,也是不能直接new。
4、内部类D,是通过public static 关键字来修饰的,进一步观察构造器,和普通的类(一个文件一个类,且是public级的)没有任何区别,所以,能够在包外直接new。
5、不能用static修饰顶级类Dog,只有内部类可以为static。