JAVA SE-注解
一个专心致志思索的人并不是在虚度光阴。虽然有些劳动是有形的,但也有一种劳动是无形的。 —— 雨果
什么是注解?注解有什么用?
- 注解就是 @xxx 这样的东西就是注解.
- 注释:给程序员看的.
- 注解:给程序看。
- 使用注解的目的: 其实将来使用注解目的就是为了代替传统配置文件.
@Override
public class Demo1 implements Person {
@Override
//向编译器描述,该方法是被重写的.
//帮你检查,被注解修饰方法是否是被重写的,如果不是编译报错!
//@Override 1.5版本只接受继承性质的重写. 1.6版本也接受实现接口性质的重写
public void eat() {
}
//@Override
public void eat2() {
}
}
@Deprecated
public class Demo2 {
@Deprecated
//该注解告诉编译器,被修饰的方法是过时方法
public static void show(){
System.out.println("hello world!");
}
public static void main(String[] args) {
Demo2.show();
}
}
@SuppressWarnings
public class Demo3 {
//@SuppressWarnings({"null","rawtypes", "unchecked"})
@SuppressWarnings("all")
//告诉编译器,不要检查什么错误!
//如果填写all,那么什么错误都不检查.
public static void main(String[] args) {
String str = null;
str.substring(0);
//@SuppressWarnings("unused")
String str2 = null;
List list = new ArrayList();
list.add("abc");
}
}
如何自定义一个注解?
public @interface MyAnnotation {
//声明属性=> 抽象方法
//声明一个名为name的属性 类型是String
String value();
//如果注解中,必填属性只有一个. 这个属性的名字是"value".那么在赋值时不需要加属性的键.
}
分析一下注解的本质:
将其.class文件找到,反编译.
@interface MyAnnoation{}
反编译后的结果
interface MyAnnotation extends Annotation
{
}
结论:注解本质上就是一个接口。它扩展了java.lang.annotation.Annotation接口;
在java中所有注解都是Annotation接口的子接口。
注解也是jdk1.5的一个新特性.
注解的属性
注解的成员
注解本质上就是一个接口,那么它也可以有属性和方法。
但是接口中的属性是 static final的,在注解中注解没有什么意义。
在开发中注解中经常存在的是方法。而在注解中叫做注解的属性.
注解的属性的类型:
1.基本类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
public @interface MyAnnotation2 {
//注解的属性都支持那些类型?
// 八大基本数据类型
// String
// Array
// Enum枚举
//可以使用default关键字,添加属性的默认值
byte a() default 10;
short b();
int c();
long d();
float e();
double f();
char g();
boolean h();
String i();
String[] j();
ElementType k();
}
关于注解的属性声明后的使用:
1.如果一个注解有属性,那么在使用注解时,要对属性进行赋值操作.
例如:@MyAnnotation3(st = "aaa")
2.如果一个注解的属性有多个,都需要赋值,使用","分开属性.
@MyAnnotation3(st = "aaa",i=10)
3.也可以给属性赋默认值
double d() default 1.23;
如果属性有默认值,在使用注解时,就可以不用为属性赋值。
4.如果属性是数组类型
1.可以直接使用 属性名={值1,值2,。。。}方式,例如
@MyAnnotation3(st = "aaa",i=10,sts={"a","b"})
2.如果数组的值只有一个也可以写成下面方式
@MyAnnotation3(st = "aaa",i=10,sts="a")
注意sts属性它是数组类型,也就是说,只有一个值时,可以省略"{}"
5.对于属性名称 value的操作.
1.如果属性名称叫value,那么在使用时,可以省略属性名称
@MyAnnotation3("hello")
2.如果有多个属性,都需要赋值,其中一个叫value,这时,必须写属性名称
@MyAnnotation3(value="hello",i=10)
3.如果属性名称叫value,它的类型是数组类型.
1.只有这个value属性
可以直接赋值,不能写属性名称,但是,如果只有一个值
@MyAnnotation3({"abc"})或 @MyAnnotation3("abc")
但是如果有多个值
@MyAnnotation3({"abc","def"})
2.如果有多个属性,属性名称叫value
所有属性都需要赋值,那么必须写属性名称.
关于元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited
四种。
//元注解 (4个)
//修饰注解的注解
// @Retention 注解是给谁看的=> 永远选择RUNTIME
//RetentionPolicy.SOURCE 注解会保留到编译期 (给编译器看)
//RetentionPolicy.CLASS 注解会保留到加载期(给类加载器)
//RetentionPolicy.RUNTIME 注解会保留到运行期(给虚拟机看)
//
@Retention(RetentionPolicy.RUNTIME)
//@Target 注解支持加在什么位置
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD,ElementType.TYPE})
//@Inherited描述 注解可否被继承
@Inherited
//@Documented 描述注解是否用于生成java文档
@Documented
public @interface MyAnnotation3 {
}
注解与银行取款的实例
首先自定义一个注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BankInfo {
double value();
}
实现的银行业务类
public class BankService {
@BankInfo(20000)
public static void zz(String name1,String name2,double money) throws Exception{
// 在使用注解的方法中获得注解上填写的属性值.
//1 获得注解所在的反射对象
Method m = BankService.class.getMethod("zz",String.class,String.class,double.class);
//2 判断方法是否被@BankInfo 所修饰
if(m.isAnnotationPresent(BankInfo.class)){
//被修饰
//3 获得注解的属性值
BankInfo info = m.getAnnotation(BankInfo.class);
double maxmoney = info.value();
if(money>maxmoney){
throw new RuntimeException("单次转账不能超过"+maxmoney+"元!");
}
System.out.println(name1+"给"+name2+"转了"+money+"元!");
}else{
//没被注解修饰
throw new RuntimeException("系统异常,不能转账!");
}
}
public static void main(String[] args) throws Exception {
zz("tom", "jerry", 10000);
}
}
下一个事例:JDBCUtils
在以往的实例当中,我们选择以配置文件的方式来控制参数,现在我们可以用注解来完成相关参数的配置工作。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//加到类上
public @interface JDBCInfo {
//驱动名称
String driver();
//url地址
String url();
//用户名
String name();
//密码
String password();
}
重写JDBC的工具类
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
@JDBCInfo(driver = "com.mysql.jdbc.Driver", name = "root", password = "1234", url = "jdbc:mysql://localhost:3306/day05")
public class JDBCUtils {
private static String driver;
private static String url;
private static String user;
private static String password;
static{
try {
//获得注解中配置的属性
//1 获得注解所在的反射对象
Class clazz = JDBCUtils.class;
//2 获得注解的实现类
JDBCInfo info = (JDBCInfo) clazz.getAnnotation(JDBCInfo.class);
//3 获得4个属性值
driver = info.driver();
url=info.url();
user=info.name();
password=info.password();
//1 注册驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//1 获得连接
public static Connection getConnection(){
Connection conn = null;
try {
//2 获得连接
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("创建连接失败!");
}
return conn;
}
//2 释放资源
//1> 参数可能为空
//2> 调用close方法要抛出异常,确保即使出现异常也能继续关闭
//3>关闭顺序,需要从小到大
public static void close(Connection conn , Statement st , ResultSet rs){
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(st!=null){
st.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
System.out.println(getConnection());
}
}