栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

对比C#的Attribute和Java的@Annotion的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

对比C#的Attribute和Java的@Annotion的使用

前言:

注解@Annotion是Java非常重要的一部分,
自从1.5版本推出以来就被非常广泛的运用到各种框架和应用,
已经成为了Java一块重要的拼图了.
而C#的Attribute和@Annoation的功能相近,
同样也是配合二者反射的使用给类/接口/…添加动态的运行时的信息

这里先以Java使用Annoation为例,

Java使用Annoation:山寨一个@Bean

@Bean是spring的一个最基础的注解,
只要添加后就可会为类和方法在容器中创建一个实例
这个功能并不难,在不限制生命周期的情况下,现在我们可以自己实现一下

1.定义一个容器(其实就是一个Map)
public class MySpringContainer {
	
	public static HashMap theContainer = new HashMap();
	
	public static HashMap getContainer(){
		return theContainer;
	}

}
2.定义注解@Bean

注解的定义只需要记住4个元注解即可

  1. @Target({ElementType枚举类,用于规定注解的使用范围})
  2. @Retention(RetentionPolicy枚举类型,用于指定注解信息的保留,有Souce只保留在编译时,Class保存在编译后的类文件,RUNTIME在(VM)程序运行时也保留)
  3. @documented
  4. @Inherited //是否可以被继承,这点很常见,在spring中,@Component继承了@Bean,@Servce,@Controller,@Repository…则继承了@Component
@Target({ElementType.TYPE})   //可以设置在类上
@Retention(RetentionPolicy.RUNTIME) //保留策略
@Inherited
@documented
public @interface Bean {
	
	//注解的定义和接口很像,同样也只能在其中声明方法(但其方法本质是一种属性,不需要实现,这是和接口不一样的)
	String O_id();
	
}

3.随便定义一个pojo类,应用注解
@Bean(O_id = "theOne")   //tip:如果方法名为value则可以不用写O_id
public class Pet {
	
	private String id;
	
	private String name;
	
	private String Owner;

	public String getId() {
		return id;
	}
	public Pet() {
		System.out.println("使用了無參的構造方法");
		id = "deffault";
		name = "deffault";
		Owner = "deffault";
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getOwner() {
		return Owner;
	}
	public void setOwner(String owner) {
		Owner = owner;
	}
}
4.使用反射在运行时获取注解

在完成定义后,需要获取类信息,并在类信息上再获取注解信息,
在这里写个简单的类扫描工具,用于检查指定包下类的@Bean注解信息

public class PojoAnnotionScanner {
	
	
	public static void Scan(String packageName) throws Exception {
		List list = getClazzesInPackage(packageName);
		list.forEach(claz->{
			//检查Class中是否有Bean标签
			if(claz.getAnnotation(Bean.class)!=null) {
				Bean bean = (Bean) claz.getAnnotation(Bean.class);
				Object obj = new Object();
				try {
					obj = claz.newInstance();
				} catch (Exception e) {
					e.printStackTrace();
				} 
				//有的话就把用Class的反射获取的对象和注解信息放到我们的山寨容器
				MySpringContainer.getContainer().put(bean.O_id(), obj);
			}
			
		});
	}
	//获取指定报名下,所有类的Class集合
	private static List getClazzesInPackage(String packageName) throws Exception {
		ArrayList list = new ArrayList<>();
		//獲取包路徑
		String packpath = packageName.replace('.', '/');
		//獲取包的URL
		URL pURL = Thread.currentThread().getContextClassLoader().getResource(packpath);
		//獲取包文件夾,準備遍歷下面的.class文件
		File dic = new File(pURL.getPath());
		if(!dic.exists())
			throw new Exception("包路徑不正確!");
		File[] files = dic.listFiles(filename->{
			if(filename.getName().endsWith(".class"))
				return true;
			return false;});
		
		for(File item : files ) {
			String totalpath = packageName+"."+FilenameUtils.getbaseName(item.getName());
			Class claz = Class.forName(totalpath);
			list.add(claz);
		}
		
		return list;
	}

}

运行测试:

public static void main(String[] args) throws Exception {
		//扫描后就可以到我们的容器中去查找这个创建的对象
		PojoAnnotionScanner.Scan("pojo");
		Pet the = (Pet) MySpringContainer.theContainer.get("theOne");
		System.out.println(the.getId()+the.getName()+the.getOwner());
}

运行结果:

使用了無參的構造方法
deffaultdeffaultdeffault


当然,你也可以再定义一个@Value注解,给属性赋值,
然后同样去检查方法中再去通过反射获取Class中的所有Field…

C#使用Attribute同样山寨一个[Bean] 1.容器
public class MySpringContainer
{
    public static Dictionary springContainer = new Dictionary();

    public static Dictionary GetConainer()
    {
        return springContainer;
    }
}
2.定义Attribute
/// 
 /// 定義[Bean註解,限定于type類型,可以像Spring一樣創建一個實例對象]
 /// 
 ///C#的注解需要使用[AttributeUsage]修饰,三个参数分别代表了
 ///AttributeTargets注解应用类型,相当于@Target
 ///AllowMultiple是否可以在一个类/接口/方法....上重复使用
 ///Inherited是否允许被继承
 [AttributeUsage(AttributeTargets.Class,AllowMultiple = false,Inherited = true)]
 public class Bean:System.Attribute
 {
     //C#注解继承自Attribute,像一个普通类一样可以定义属性和方法,正常实例化

	 //但是当Atrribute作为注解应用在类/接口/方法...上时,只能用它的构造函数接收参数或给属性赋值
	 //所以可以定义很多构造函数来接收不同形式的参数,
	 //这点和Java的@Annotion方式不同,但目的一样那就是把信息保存到注解里
     public string O_ID { get; }

     public Bean(string O_ID)
     {
         this.O_ID = O_ID;  
     }
 }
3.poco类
 [Bean("TheSingle")]
 public class Pet
 {
     public string ID  { get; set; }

     public string Name { get; set; }

     public string OwnerName { get; set; }

     public Pet()
     {
         ID = "DefaultID";
         Name = "DefaultName";
         OwnerName = "張三";
     }
     public override string ToString()
     {
         return "寵物ID:" + ID + "名字:" + Name + "主人名:" + OwnerName;
     }
 }
4.反射获取注解
public static void Scan(string packageName)
{
	//C#获取dll中所有类的Type非常简单
    List list = Assembly.Load(packageName).GetTypes().ToList();
	//遍历Type集合判断是否有Bean的Attribute,
    list.ForEach(type =>
    {
        if (type.GetCustomAttribute(typeof(Bean))!=null)
        {
        	//如果有的话就在容器里注册一个该类型的实例
            Bean bean = (Bean)type.GetCustomAttribute(typeof(Bean));
            MySpringContainer.GetConainer().Add(bean.O_ID, Activator.CreateInstance(type));
        }
    });
       
}

测试:

static void Main(string[] args)
{
    ClassScanner.Scan("AttributeTest");
    Pet pet1 = (Pet)MySpringContainer.springContainer["TheSingle"];
    Console.WriteLine(pet1);  
}
总结:

同:
无论是Attribute还是@Annoation都需要服务于反射
都是在运行时添加的动态信息
异;
Attribute可以本质是一种普通的类,@Annotion不是类也不是借口
Attribute通过其构造函数保存信息,@Annoation通过方法属性

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/677583.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号