【Java 强化】代码规范,springcloud 视频
private static Map<String, IUSB> plugins = new HashMap<>();
//-----------------------静态代码快加载资源文件-------------------------
static {
Properties p = new Properties();
// 从 classpath 的根路径去加载 plugins.properties 文件
try (InputStream is = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("plugins.properties"))
{
p.load(is);
// 读取 properties 文件, 创建 USB 组件对象
Set<Entry<Object, Object>> entrys = p.entrySet();
for (Entry<Object, Object> entry : entrys) {
// 资源文件中读取到的类名
String className = entry.getValue().toString();
// 通过反射利用类名创建对象
IUSB usbObject = (IUSB)Class.forName(className).newInstance();
plugins.put(entry.getKey().toString(), usbObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//-------------------------------------------------------------------
// 将配件插在主板上
public void install(String name, IUSB usb) {
plugins.put(name, usb);
}
// 从主板上卸载指定的配件
public void uninstall(String name) {
plugins.remove(name);
}
// 主板通信, 让每个配件都工作
public void doWork() {
for (IUSB usb : plugins.values()) {
usb.swapData();
}
}
}
此时 APP
中的代码将变得十分简洁,我们无需再手动创建配件对象再调用主板的 install
,我们只需要维护好配置文件 plugins.properties
中的内容即可。
比如,我们写一个键盘类 Keyboard
:
public class Keyboard implements IUSB{
@Override
public void swapData() {
System.out.println("键盘在跳舞");
}
}
我们只需要将它添加到配置文件中即可。
key=value
mouse = com.yusael._01_review.Mouse
keyboard = com.yusael._01_review.Keyboard
APP
中的代码是不需要动的。
public class App {
public static void main(String[] args) {
// 主板对象,
MotherBoard board = new MotherBoard();
// 调用主板的通信
board.doWork();
System.out.println("-----------------------");
}
}
键盘在跳舞
鼠标在移动
[](
)JavaBean 规范
==============================================================================
JavaBean 是一种 JAVA 语言写成的可重用组件(类),必须遵循一定的规范:
类必须使用
public
修饰必须保证有公共无参数构造器
包含了属性的操作手段(
getter
,setter
)
分类:
复杂:UI,比如
Button
、Panel
、Window
类简单:
domain
、dao
、service
组件、封装数据、操作数据库、逻辑运算等
成员:
方法:
Method
事件:
event
属性:
property
属性:
attribute
:表示状态,Java 中没有该概念,很多人把 字段(Field) 称之为 属性(attribute)property
:表示状态,但是不是字段,是字段的操作方法(getter
/setter
)决定的
框架中使用的大多是是属性。
设置字段值:writeMethod: setter
方法:
public void setXxx(数据类型 变量){
赋值操作;
}
若:setName
----> 属性:name
若:setUserName
----> 属性:userName
若:setISBN
----> 属性:ISBN
获取字段值:readMethod: getter
方法:
public 数据类型 getXxx(){
return 结果值;
}
若:getName
----> 属性:name
若:getUserName
----> 属性:userName
若:getISBN
----> 属性:ISBN
若:数据类型是 boolean
,则不叫 get 方法,而是 is 方法,如:isEmpty
标准的属性:一般提供字段,Eclipse 生成 getter/setter
,字段和属性同名
是否需要同时提供 getter/setter
:
public class User{
private String firstName; // 名
private String lastName; // 性别
//在数据库只需要存储全名
public void setFullName(String fullName){}
}
面试题:说说 JavaBean 和 EJB 的区别。
[](
)Lombok 工具(减少代码量)
===================================================================================
一、Lombok 是什么
Lombok 是一款小巧的代码生成工具。官方网址:[http://projectlombok.org/](
)
Lombok 主要特性有:自动生成默认的 getter/setter
方法、自动化的资源管理(通过@Cleanup
注解)及注解驱动的异常处理等。目前在国外广泛应用。
Lombok 它和 jquery 一样,目标是让程序员写更少的代码,以及改进一些原始语法中不尽人意的地方。Lombok 能做到这一点。既不是用 annotations process,也不是用反射。而是直接黑到了编译过程中。所以对运行效率没有任何影响,我们可以通过反编译 class 文件进行验证。
二、为何项目中要引入 Lombok
提高开发效率
使代码直观、简洁、明了、减少了大量冗余代码(一般可以节省 60%-70%以上的代码)
极大减少了后期维护成本
修改变量名不需要再手动修改
getter/setter
三、使用 Lombok
给 Eclipse 安装插件,识别语法
在项目中引入 lombok 包
使用其中的注解(标签)
注意:构造器 和 toSring
也可以使用 lombok,但是建议写出来,看的更明显。
import lombok.Getter;
import lombok.Setter;
@Getter@Setter
public class Person {
private Long id;
private String name;
private Integer age;
public Person(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
Ctrl + O 可以看到当前类的字段和方法:getter/setter
已经存在。
[](
)内省机制(Introspector)(重要)
=========================================================================================
内省机制作用:查看和操作 JavaBean 中的属性
获取 JavaBean 中的每一个属性名/属性类型
通过 getter 方法获取属性值;通过 setter 方法给属性设置值
首先创建一个类 User
:
public class User {
private String name;
private int age;
private boolean man;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isMan() {
return man;
}
public void setMan(boolean man) {
this.man = man;
}
}
下面是一个关于内省机制的例子:
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
// 内省机制: 操作 User 类值的属性
public class IntrospectorDemo {
public static void main(String[] args) throws Exception {
// 1:获取 JavaBean 的描述对象
BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class);
User u = User.class.newInstance();
// 2:获取 JavaBean 中的属性的描述器
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
System.out.println(u); // 证明是同一个对象
for (PropertyDescriptor pd : pds) {
// 获取当前属性的名称
System.out.println("属性名 = " + pd.getName());
// 获取当前属性的 getter 方法
System.out.println("getter : " + pd.getReadMethod());
// 获取当前属性的 setter 方法
System.out.println("setter : " + pd.getWriteMethod());
System.out.println("--------------------------------");
if ("name".equals(pd.getName())) {
Method setter = pd.getWriteMethod(); // 获取方法
setter.invoke(u, "Jack"); // 调用方法
}
}
System.out.println(u);
}
}
[](
)apache 的 commons 项目(了解)
=========================================================================================
这部分内容了解一下就可以,知道 apache 有很多强大的项目,commons 是其中之一。
[](
)JavaBean 和 Map 相互转换(自行实现)
JavaBean 拥有多组属性名和属性值,每一个属性名称对应一个属性值,属性名称不同。
Map 拥有多组 key-value,每一个 key 对应一个 value,key 不同。
如果把 JavaBean 中的属性名称看做是 Map 中的 key,二者就是等价的。
把 JavaBean 转换为 Map 对象:
public static Map<String,Object> bean2map(Object bean){}
把 Map 对象转换为 JavaBean:
public static Object map2bean(Map<String,Object> beanMap,Class beanType){}
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import com.yusael._02_javabean.Person;
// JavaBean 的工具类
public class BeanUtil {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setId(123L);
p.setName("Jack");
p.setAge(18);
// JavaBean -> Map
Map<String, Object> map = bean2map(p);
System.out.println(map);
// Map -> JavaBean
Person obj = map2bean(map, Person.class);
System.out.println(obj);
}
// 把 JavaBean 对象转换为 Map
public static Map<String, Object> bean2map(Object bean) throws Exception {
Map<String, Object> map = new HashMap<>();
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String name = pd.getName(); // 属性名称
Object value = pd.getReadMethod().invoke(bean); // 调用 getter 方法, 获取属性值
map.put(name, value);
}
return map;
}
// 把 Map 转换为 JavaBean
public static <T> T map2bean(Map<String, Object> map, Class<T> beanType) throws Exception {
// 创建 JavaBean 对象
Object obj = beanType.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(beanType, Object.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// 从 Map 中获取和属性同名的 key 的值
Object value = map.get(pd.getName());
// 调用 setter 方法, 设置属性值
pd.getWriteMethod().invoke(obj, value);
}
return (T)obj;
}
}
[](
)commons-beanutils(了解、体验一下使用即可)
这部分了解一下即可,大概体验一下这些工具类的作用。。。
需要 jar 包:commons-beanutils-1.9.4.jar
、commons-logging-1.2.jar
;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import com.yusael._02_javabean.Person;
public class BeanUtilsDemo {
public static void main(String[] args) throws Exception {
Person p = new Person();
Map<String, Object> map = new HashMap<>();
map.put("id", "17210224");
map.put("name", "Jack");
map.put("age", "20");
System.out.println(p);
BeanUtils.copyProperties(p, map);
System.out.println(p);
}
}
转换时的一些细节:直接转换 long
类型的缺省值为 0,需注册为 Long
,缺省值才为 null;
日期类转换的细节:beanutils 不支持 String --> Date 转换,需要手动设置转换模式。
[](
)注解(Annotation)
=================================================================================
[](
)初始注解
Java5 开始,java 开始对元数据的支持,也就是 Annotation
(注解 / 标签)
元数据(metadata):描述数据的数据
注解被用来为程序元素(类,方法,成员变量等)设置元数据。
所有的 Annotation
都是 java.lang.annotation.Annotation
接口的子接口
Annotation
是一种特殊的接口(好比枚举是特殊的类);
@interface Override {} ---> interface Override extends java.lang.annotation.Annotation{}
所有的枚举类,都是
java.lang.Enum
类的子类
enum Gender{} ---- > class Gender extends java.lang.Enum{}
使用注解需要注意,必须有三方参与才有意义:
得有注解标签;
被贴的程序元素(类、字段、构造器、方法等);
由第三方的程序来赋予注解特殊的功能(也是 Java 代码);
[](
)JDK 自带的注解
@Override
:限定覆写父类方法@Deprecated
:标记已过时不推荐使用
在 JDK1.5 之前,使用文档注释来标记过时
@SuppressWarings
:抑制编译器发出的警告
@SuppressWarings(value="all")
@SafeVarargs
:抑制堆污染警告(Java7 开始出现的)
该注解仅仅是抑制住编译器不要报警告,但是存在的风险依然存在。
使用注解存在的疑惑:
为什么有的注解可以贴在类上/方法上/变量上,而有些却不行?
肯定有东西来约束注解贴的位置。
为什么有的注解可以接受参数,比如
@SuppressWarings(value="all")
,而有的注解却不行。
通过查看注解的源代码,发现注解中存在抽象方法才可以使用参数。
[](
)元注解(@Retention、@Target、@Documented、@Inherited)
元注解:注解的元数据 —> 定义注解时,注解上的注解。
@Retention
: 表示注解可以保存在哪一个时期;保存的时期的值,封装在 RetentionPolicy
枚举类中;一般自定义的注解,使用RUNTIME
(使用反射赋予注解功能)
SOURCE
:注解只能存在于源文件中,编译之后,字节码文件中没有。CLASS
: 注解可以存在于源文件和字节码文件中,无法加载进 JVM。RUNTIME
:注解可以存在于源文件,字节码文件,JVM 中。
@Target
:表示注解可以贴在哪些位置(类、方法、构造器上等等)
位置的常量封装在 ElementType
枚举类中:
* ElementType.ANNOTATION_TYPE
:只能修饰 Annotation
* ElementType.CONSTRUCTOR
:只能修饰构造方法
* ElementType.FIELD
:只能修饰字段,包括枚举常量
* ElementType.LOCAL_VARIABLE
:只能修饰局部变量
* ElementType.METHOD
:只能修饰方法
* ElementType.PACKAGE
:只能修饰包(极少使用)
* ElementType.PARAMETER
:只能修饰参数
* ElementType.TYPE
:只能修饰类,接口,枚举
@Documented
: 使用 @Documented
标注的标签会保存到 API 文档中
@Inherited
: @Inherited
标注的标签可以被子类所继承
@Target(RetentionPolicy=RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface A{} // 定义一个 A 标签
@A
class SuperClass{} // 使用 A 标签
// SubClass 是 SuperClass 的子类
// 使用反射来检测 SubClass, 发现 SubClass 类上也有 A 标签
// 说明 A 标签 被继承了
class SubClass{}
[](
)注解的定义和使用
注解的定义语法:
@Target(ElementType.TYPE) // 标识该注解可以贴在类上/接口上
@Retention(RetentionPolicy.RUNTIME) // 标识该注解可以存在于 JVM 中(通过反射赋予功能)
public @interface 注解名称 {
// 抽象方法-->属性
返回类型 方法名称() default 值;
...
}
注意:注解中 抽象方法(属性) 类型
只能是 基本类型、
String
、Class
、annotation
、枚举 、数组当只有一个属性并且名称为 value,此时可以省略 value
// @VIP(value="xx")
评论