java构造器复用方式
作者:chuanzhangsss
这篇文章主要介绍了java构造器复用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
构造器复用
创建一个Employee类,属性有(名字,性别,年龄,职位,薪水),提供3个构造方法,可以初始化(⑴)(名字,性别,年龄,职位,薪水),(2)(名字,性别,年龄)(3)(职位,薪水).要求充分复用构造器Hello.java
public class Hello { public static void main(String[] args) { } } class EMployee{ String name; char gender; int age; String job; double sal; // 职位 薪水 public EMployee(String job,double sal) { this.job = job; this.sal = sal; } // 姓名 性别 年龄 public EMployee(String name,char gender,int age) { this.name = name; this.gender = gender; this.age = age; } // 名字 性别 年龄 职位 薪水 public EMployee(String job,double sal,String name,char gender,int age) { this(name,gender,age); this.job = job; this.sal = sal; } }
推荐使用构造器注入
Spring框架对Java开发的重要性不言而喻,平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合。
前几天的时候,朋友问我为什么要使用构造器的注入方式,后面抽时间了解了一下,下面就是笔者要讨论的就是其注入方式。
常见的三种注入方式
field注入
@Controller public class FooController { @Autowired //@Inject private FooService fooService; //简单的使用例子,下同 public List<Foo> listFoo() { return fooService.list(); } }
这种注入方式应该是笔者目前为止开发中见到的最常见的注入方式。原因很简单:
- 注入方式非常简单:加入要注入的字段,附上
@Autowired
,即可完成。 - 使得整体代码简洁明了,看起来美观大方。
构造器注入
@Controller public class FooController { private final FooService fooService; @Autowired public FooController(FooService fooService) { this.fooService = fooService; } //使用方式上同,略 }
setter注入
@Controller public class FooController { private FooService fooService; //使用方式上同,略 @Autowired public void setFooService(FooService fooService) { this.fooService = fooService; } }
构造器注入的好处
- 依赖不可变:其实说的就是final关键字,这里不再多解释了。不明白的园友可以回去看看Java语法。
- 依赖不为空(省去了我们对其检查):当要实例化FooController的时候,由于自己实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:1、有该类型的参数->传入,OK 。2:无该类型的参数->报错。所以保证不会为空,Spring总不至于传一个null进去吧 😦
- 完全初始化的状态:这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法,这里不详细展开。)。所以返回来的都是初始化之后的状态。
//承接上面field注入的代码,假如客户端代码使用下面的调用(或者再Junit测试中使用) //这里只是模拟一下,正常来说我们只会暴露接口给客户端,不会暴露实现。 FooController fooController = new FooController(); fooController.listFoo(); // -> NullPointerException
如果使用field注入,缺点显而易见,对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。而且将一直是个潜在的隐患,因为你不调用将一直无法发现NPE的存在。
还值得一提另外一点是:使用field注入可能会导致循环依赖,即A里面注入B,B里面又注入A:
public class A { @Autowired private B b; } public class B { @Autowired private A a; }
如果使用构造器注入,在spring项目启动的时候,就会抛出:
BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference?
从而提醒你避免循环依赖,如果是field注入的话,启动的时候不会报错,在使用那个bean的时候才会报错。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。