JAVA基础知识之Annotation
基本Annotation
Annotation必须使用工具(APT, Annotation tool)才能处理,Annotation可以在编译,类加载,运行时被读取,并执行相应处理。
下面介绍一些常用Annotation.
@Override
强制一个子类必须覆盖父类的方法,这样如果在子类中将需要覆盖的方法名写错了,在编译阶段就可以被发现
@Deprecated
标记某个类,方法等已经过时,编译时会有警告
@SuppressWarnings
将会取消编译器的警告。将对程序元素及下面所有子元素起作用。
用法举例,
package Annotation; import java.util.ArrayList;
import java.util.List; public class SuppressWarningsTest {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
@SuppressWarnings("rawtypes")
List<String> list = new ArrayList();
list.add("aa");
}
}
@SafeVarargs
Java7 堆污染 警告
把一个不带泛型的变量赋值给带泛型的变量时,往往会发生 堆污染,例如下面的情况
List list = new ArrayList<Integer>();
//添加元素时引发unchecked异常
list.add(20);
//下面的代码将引起“未经检查的转换”警告,编译、运行时候正常
List<String> ls = list;
//但是访问ls里的元素就会引起运行时异常
System.out.priintln(ls.get(0));
对于形参个数可变的方法,如果形参又是泛型,就更容易引起 堆污染,例如工具类
public class ErrorUtils
{
public static void faultyMethod(List<String>...listStrArray)
{
...
List[] listArray = listStrArray;
...
}
}
JAVA6以前,编译器在编译faultyMethod()方法时并不会发出警告,但是在使用这个方法的时候却发出警告:ClassCastException,
在JAVA7开始,编译器在编译ErrorUtils的时候就发出警告,可见JAVA7更严谨。
但是在某些情况下,开发者并不希望看到这种警告,于是可以用三种方法屏蔽,
@SafeVarargs , JAVA7推荐的方式,专门用来屏蔽 堆污染 警告
@SuppressWarnings("unchecked"),取消所有警告
@编译时使用-Xlint:varargs选项,不常用。
@FunctionalInterface
函数式接口限定,
JAVA 8中规定,如果接口中只有一个抽象方法(可以用多个其他方法),该接口就是函数式接口。
而@FunctionalInterface就是做这种编译检查的,如果在一个抽象接口中有两个以上抽象方法,就不再是函数式接口,编译器就会报错。
JDK的元Annotation
除了java.lang下的5个基本的Annotation之外,JDK还在java.lang.annotation下提供了6个Meta Annotation (元 Annotation). @Repeatable用来专门定义java8的重复注解。 其他的几个Annotation(@Retention, @Target, @Documented, @Inherited)则用来修饰其他的Annotation定义。
@Retention
用来修饰别的Annotation, 指定被修饰的Annotation的作用范围候(java文件中,还是class文件中,还是运行时)。
@Retention的使用格式为 @Retention(value=xxxx),也可以简化为@Retention(xxxx),当注解的成员变量只有"value"时就可以简写。
value可以有以下三中取值
- RetentionPolicy.SOURCE: 仅在源码中可见,被修饰的Annotation只保留在java源码中,编译时直接丢弃。
- RetentionPolicy.CLASS:保留在CLASS文件中,java程序运行时候不会读取。 这是默认值。
- RetentionPolicy.RUNTIME,在运行时可见,也是记录在CLASS文件中,但是在运行的时候JVM还会从被修饰的Annotation中提取信息,程序也可以通过反射获取Annotation中的信息。
用法举例,
//下面被@Retention修饰的注解Testable将会保留到运行时
@Retention(value=RetentionPolicy.RUNTIME)
//上面一行也可以简写为
//@Retention(RetentionPolicy.RUNTIME)
public @interface Testable{}
@Target
也是用来修饰别的Annotation. 用于指定被修饰的Annotation只会对哪些程序元素(构造器,成员变量,成员方法等)起作用。value的取值如下,
- ElementType.ANNOTATION_TYPE:指定该策略的annotation只能用来修饰Annotation
- ElementType.CONSTRUCTOR:只能修饰构造器
- //以下value取值可顾名思义
- ElementType.FIELD
- ElementType.LOCAL_VARIABLE
- ElementType.METHOD
- ElementType.PACKAGE
- ElementType.PARAMETER
- ElementType.TYPE:可修饰类,接口(包括注解类型)或枚举定义。
用法举例
@Target(ElementType.FIELD)
//只能修饰成员变量
public @interface ActionListenerFor{}
@Documented
用来修饰别的annotation. 被修饰的annotation也会被javadoc提取
例如下面的用法,
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
//定义Testable Annotation会被javadoc工具提取
@Documented
public @interface Testable {}
在具体类中使用
public class MyTest
{
//@Testable也会被javadoc提取
@Testable
public void info()
{
...
}
}
@Inherited
用来修饰其他annotion, 被修饰的annotation具有继承性。例如下面。
定义可继承的annotation: Inheritable
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Inheritable {}
在基类上使用Inheritable,
//使用@Inheritable修饰的Base类
@Inheritable
class Base {}
Base的子类中,即使没有显示使用Inheritable Annotation, 但会从父类继承,
//使用@Inheritable修饰的Base类
@Inheritable
class Base {}
4 public class InheritableTest extends Base {}
自定义的Annotation
除了java.lang下的4个基本annotation,我们也可以自定义annotation.
自定义annotation
根据annotation是否可以包含成员变量,可以把annotation分为如下两类,即
- 标记Annotation:无成员变量,只利用自身是否存在来提供信息,例如@Override
- 元数据Annotation:包含成员变量,接收更多元数据。
定义一个annotation的方式与定义接口非常相似(继承自Annotation接口),以@inteface开头,可以有成员变量(及默认值),比如下面这样,
//自定义一个annotatio,包含两个成员变量,而且有默认值
public @interface MyTag
{
String name() default "xiao ming"
int age() default 2
}
下面是使用我们自定义的annotation
public class Test
{
@MyTag(name="xx", age=6)
public void info()
{
...
}
...
}
提取Annotation信息
Annotation不会自己生效,而是需要写专门的程序来提取这些信息。从Java5开始,java.lang.reflect提供的反射API增加了运行时读取Annotation的能力,
当然只有将Annotation定义成@Retention(RetentionPolicy.RUNTIME)修饰,该Annotation才会在运行时可见。
Java5在java.lang.reflect下增加了AnnotatedElement接口,代表程序中可以接受注解的程序元素,主要实现类有Class, Constructor, Field, Method, Package等。AnnotatedElement是所有程序元素(Class, Constructor, Field, Method等)的父接口,所以当程序通过反射获取了某个类的AnnotatedElement对象(如Class, Constructor, Field, Method等)之后,就可以用下面方法访问Annotation的信息。
<A extends Annotation> A getAnnotation(Class<A> annotationClass) , 返回程序元素上指定类型的annotation
<A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) , JDK8新增。 获取直接修饰程序元素的指定类型的annotation
Annotation[] getAnnotations(): 返回程序元素上的所有注解
Annotation[] getDeclaredAnnotations(); 返回直接修饰该程序元素的所有Annotation
boolean isAnnotationPresent(Class<? extends Annotation) annotationClass. 元素上是否存在指定类型的annotation
<A extends Annotation> A[] getAnnotationByType(Class<A> annotationClass , JDK8中允许重复注解,获取修饰该程序元素指定类型的多个annotation
<A extends Annotation> A[] getDeclaredAnnotationByType(Class<A> annotationClass , JDK8中允许重复注解,获取直接修饰该程序元素指定类型的多个annotation
下面举例,
//获取Test类的info方法的所有注解
Annotation[] aArray = Class.forName("Test").getMethod("info").getAnnotations();
//遍历
for (Annotation an : aArray)
{
System.out.println(an); //如果要获取某个注解里的元数据,则可以将注解强制类型转换成所需注解类型,
//然后通过注解对象的抽象方法来访问这些元数据
// 如果tag注解是MyTag1类型
if (tag instanceof MyTag1) {
System.out.println("Tag is : "+tag);
//强制转换
System.out.println("tag.name(): "+((MyTag1)tag).method1());
System.out.println("tag.name(): "+((MyTag1)tag).method2());
}
// 如果tag注解是MyTag2类型
if (tag instanceof MyTag1) {
System.out.println("Tag is : "+tag);
//强制转换
System.out.println("tag.name(): "+((MyTag2)tag).method1());
System.out.println("tag.name(): "+((MyTag2)tag).method2());
}
}
下面这个例子,模拟JUnit的@Test注解,即只有在方法上加了@Test注解之后,JUnit才会执行这个方法。
首先自定一个Testable注解, 要@Retention来限定注解在程序运行时也有效,
package ann; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; //自定义一个注解Testable,使用JDK的两个元注解来修饰他它。Retention设置注解保留时间到运行时,Target设置注解只对方法起作用
@Retention(value=RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Testable{ }
写一个测试目标类MyTest,里面有8个方法,但是只有5个加了@Testable注解,
package ann; public class MyTest {
//使用@Testable注释的方法指定该方法是可测试的
@Testable
public static void m1() { } public static void m2() { } @Testable
public static void m3() {
throw new IllegalArgumentException("参数错误!");
} @Testable
public static void m4() { } @Testable
public static void m5() { } public static void m6() { } @Testable
public static void m7() { } public static void m8() { }
}
如前面所说,注解并不会自动起作用,而是需要我们写额外的代码,通过反射去获取注解信息,并执行相应操作,
下面写一个专门的注解处理类,用来读取MyTest类中的Testable注解,从而控制MyTest类中哪些方法可以执行,
package ann; import java.lang.reflect.Method; public class ProcessorTest {
public static void process(String clazz) throws SecurityException, ClassNotFoundException {
int passed = 0;
int failed = 0;
//遍历clazz对应类中的所有方法
for (Method m : Class.forName(clazz).getMethods() ) {
// 如果该方法使用了@Testable注解
if (m.isAnnotationPresent(Testable.class)) {
try {
//调用m方法
m.invoke(null);
//测试成功,passed加1
passed++;
} catch (Exception ex) {
System.out.println("方法 "+m+" 运行失败,异常: "+ex.getCause());
failed++;
}
}
}
// 统计测试结果
System.out.println("共运行了: "+(passed + failed)+ " 个方法,其中成功了 "+passed+" 个,失败了 "+failed+" 个。");
}
}
再写一个测试类RunTests如下,我们执行RunTests类去测试MyTest类,实际是先通过上面的ProcessorTest类通过反射去读取MyTest类中的注解信息,决定哪些方法可以执行,就执行哪些方法,这个过程就跟JUnit一样。
package ann; public class RunTests {
public static void main(String[] args) throws SecurityException, ClassNotFoundException {
ProcessorTest.process("ann.MyTest");
}
}
执行上面的测试类可以看到如下测试结果,
方法 public static void ann.MyTest.m3() 运行失败,异常: java.lang.IllegalArgumentException: 参数错误!
共运行了: 5 个方法,其中成功了 4 个,失败了 1 个。
上面的例子只是通过反射来简单判断程序中是否有指定注解存在,下面的例子中,将读取注解的元数据信息,并根据信息做出相应操作。
下面通过注解来为Button绑定监听事件,这能简化编程,
首先自定义一个注解,将用来修饰Button,简单直观地说明Button将会使用哪个监听器
package ann; import java.awt.event.ActionListener;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface ActionListenerFor {
//定义一个成员变量,用来设置元数据
//该listener成员变量用于保存监听器实现类
Class<? extends ActionListener> listener();
}
上面的自定义注解中,定义了一个成员变量 listener(),对应一个监听器ActionListener类的子类。在下面的Button上添加@ActionListenerFor注解,通过listener成员指定Button监听器的实现类。
package ann; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel; public class AnnotationTest {
private JFrame mainWin = new JFrame("使用注解绑定事件监听器");
//使用Annotation为ok绑定事件监听器
@ActionListenerFor(listener=OkListener.class)
private JButton ok = new JButton("确定");
//使用Annotation为cancel绑定事件监听器
@ActionListenerFor(listener=CancelListener.class)
private JButton cancel = new JButton("取消");
public void init() {
//初始化界面
JPanel jp = new JPanel();
jp.add(ok);
jp.add(cancel);
mainWin.add(jp);
ActionListenerInstaller.processAnnotations(this);
mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWin.pack();
mainWin.setVisible(true);
}
public static void main(String[] args) {
new AnnotationTest().init();
}
}
对应上面两个按钮,各写一个监听实现类,
package ann; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import javax.swing.JOptionPane; public class OkListener implements ActionListener { @Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
JOptionPane.showMessageDialog(null, "单击了确认按钮");
} }
package ann; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import javax.swing.JOptionPane; public class CancelListener implements ActionListener{ @Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
JOptionPane.showMessageDialog(null, "单击了取消按钮");
} }
当然如果只是在上面AnnotationTest的注解中指定了Button的实现类,已然是无法实现Button和对应监听器的绑定的,我们需要专门写一个处理注解的类ActionListenerInstaller去处理,
package ann; import java.awt.event.ActionListener;
import java.lang.reflect.Field; import javax.swing.AbstractButton; public class ActionListenerInstaller { public static void processAnnotations(Object obj) {
// TODO Auto-generated method stub
try {
//获取obj对象的类
Class cl = obj.getClass();
//获取指定obj对象的所有成员变量,并遍历每个成员变量
for (Field f : cl.getDeclaredFields()) {
//将该成员变量设置成可自由访问
f.setAccessible(true);
//获取该成员变量上ActionListenerFor类的 Annotaion
ActionListenerFor a = f.getAnnotation(ActionListenerFor.class);
//获取成员变量f的值
Object fObj = f.get(obj);
//如果f是AbstractButton的实例,且a不为null
if (a != null && fObj != null && fObj instanceof AbstractButton) {
//获取a注解里的listener元数据(它是一个监听器)
Class<? extends ActionListener> listenerClazz = a.listener();
//使用反射来创建listenr对象
ActionListener al = listenerClazz.newInstance();
AbstractButton ab = (AbstractButton)fObj;
//为ab按钮添加事件监听器
ab.addActionListener(al);
}
}
} catch (Exception e) {
e.printStackTrace();
}
} }
上面程序通过Class<? extends ActionListener> listenerClazz = a.listener();就得到了AnnotationTest中通过注解描述的Button的监听实现类,OkListener和CancelListener。然后通过addActionListener()方法将Button和注解中对应的监听实现类进行了绑定。
这样,我们每次添加Button时,只需要一行注解,就轻松实现了事件监听器的绑定。
运行AnnotationTest,点击 确定 或者 取消 , 可以见到触发的相应事件得到了响应。程序执行效果如下,
重复注解
在JAVA8以前,如果需要在一个程序元素上添加同类型的重复注解,需要像下面这样,
@Results({@Result(name="failure", location="failed.jsp"), @Result(name="success", location="succ.jsp")})
public Action FooAction{...}
而在JAVA8后,则可以直接添加同类型的多个注解,但是需要先添加@Repeatable注解,
首先定义一个FKTag注解,
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE public @interface FKTag { String name() default "Johnny"; int age(); }
还需要定义一个FKTags注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE public @interface FKTags { FKTag[] value(); }
这样,可在定义@FKTag时,添加下面注解
@Repeatable(FKTags.class)
最后,就可以在程序元素上重复使用FKTag注解了
@FKTag(age=5) @FKTag(name="xiaoming", age=9}
实际上,JAVA8的这种写法只是以前版本的简写,其内部实现已然是数组形式的。
JAVA8中的type Annotation
JAVA8以前,Annotation只能用在程序元素声明语句上,JAVA8开始引入了Type Annotation,可以用在任何程序元素地方(声明,类型转换时,初始化对象时等等, 以实现对程序任何地方进行干涉处理的目的。让程序中编译时进行更严格的检查,增加程序的健壮性。
JAVA8以前我们通过Target指定Annotation对什么程序元素有效(类,成员变量,成员方法等),在JAVA8开始,新增Target参数ElementType.TYPE_USE使得Annotation可以用在任何地方。
例如我们先定义一个Type Annotation
@Target(ElementType.TYPE_USE)
@interface NotNull{}
下面是简单用法,
public class TypeAnnotationTest implements @NotNull Serialiable
{
//方法形参中使用Type Annotation
public static void main(@NotNull String[] args) throws @NotNull FileNotFoundException
{
Object obj = "abcd.txt"
//强制类型转换时使用Type Annotation
String str = (@NotNull String)obj;
// 创建对象时使用Type Annotation
Object win = new @NotNull JFrame("测试");
}
// 泛型中使用Type Annotation
public void foo(List<@NotNULL String> info(){}
}
可以看到用了Type Annotation之后可以在编译时更方便更严格地进行检查,增强了程序的健壮性。
编译时处理Annotation
通过我们自己编写的注解处理类 APT (Annotation Processing Tool), 可以对源码中的Annotation进行检查并处理,还能针对Annotation信息添加进额外的信息,这个机制可以大大简化我们的编程。
例如在Hibernate中,每一个数据表class文件都会对应一个*.hbm.xml文件,这个xml文件就是通过APT根据java文件中的Annotation信息在编译过程中生成的。
通过javac -processor,我们可以在编译时指定一个注解处理器,实现编译期间的注解处理。注意,这个注解处理器需要先编译好,才能用做其他类的注解处理器。
指定的注解处理器,是需要继承AbstractProcessor类,并且实现process方法。
下面来演示Hibernate的关联的xml自动生成的实现过程,
首先我们自定义三个普通的注解,分别表示数据库表名,主键字段,属性字段
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Persistent {
String table();
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Id {
String column();
String type();
String generator();
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Property {
String column();
String type();
}
我们在具体的JAVA类中使用上面三个注解,假设现在有一张数据库表person_inf, 我们为其建立一个实体类Person
@Persistent(table="person_inf")
public class Person {
@Id(column="person_id", type="integer", generator="identity")
private int id;
@Property(column="person_name", type="string")
private String name;
@Property(column="person_age", type="age")
private int age; //无参构造
public Person() {} // 有参构造
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
上面的类中使用了三种注解,但是这些注解不会自动生效,需要我们为其专门写一个注解处理类(APT)HibernateAnnotationProcessor,
在注解处理类中,我们根据注解中对类变量的属性描述,生成一个Person.hbm.xml文件,
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Set; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement; @SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({"Persistent", "Id", "Property"} )
public class HibernateAnnotationProcessor extends AbstractProcessor { @Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
PrintStream ps = null;
try {
for (Element t : roundEnv.getElementsAnnotatedWith(Persistent.class)) {
//获取类名
Name clazzName = t.getSimpleName();
//获取注解
Persistent per = t.getAnnotation(Persistent.class);
ps =new PrintStream(new FileOutputStream(clazzName + ".hbm.xml"));
ps.println("<?xml version=\"1.0\"?>");
ps.println("<!DOCTYPE hibernate-mapping PUBLIC");
ps.println(" \"-//Hibernate/Hibernate "+"Mapping DTD 3.0//EN\"");
ps.println(" \"http://www.hibernate.org/dtd/" + "hibernate-mapping-3.0.dtd\">");
ps.println("<hibernate-mapping>");
ps.println(" <class name=\""+t);
//输出per的table值
ps.println("\" table=\"" + per.table() + "\">");
for (Element f : t.getEnclosedElements()) {
//只处理成员变量上的Annotation
if (f.getKind() == ElementKind.FIELD) {
Id id = f.getAnnotation(Id.class);
if (id != null) {
ps.println(" <id name=\""
+ f.getSimpleName()
+ "\" + column=\"" + id.column()
+ "\" + type=\"" + id.type()
+ "\">");
ps.println(" <generator class=\""
+ id.generator() + "\"/>");
ps.println(" </id>");
}
//获取成员变量前的Property
Property p = f.getAnnotation(Property.class);
if (p != null) {
ps.println(" <property name=\""
+f.getSimpleName()
+"\" column=\"" + p.column()
+"\" type=\"" + p.type()
+"\"/>");
}
}
}
ps.println(" </class>");
ps.println("</hibernate-mapping>");
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (ps != null) {
try {
ps.close();
}catch (Exception ex) {
ex.printStackTrace();
}
}
} return true;
} }
执行下面两行编译语句,
javac HibernateAnnotationProcessor.java
javac -processor HibernateAnnotationProcessor Person.java
之后会发现生成了一个Person.hbm.xml文件如下,
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Person
" table="person_inf">
<id name="id" + column="person_id" + type="integer">
<generator class="identity"/>
</id>
<property name="name" column="person_name" type="string"/>
<property name="age" column="person_age" type="age"/>
</class>
</hibernate-mapping>
通过以上 javac -processer的方法,就实现了编译期间使用处理器对类的注解进行处理的目的,上面生成的xml文件就可以供Hibernate后面使用。
JAVA基础知识之Annotation的更多相关文章
- 学习Spring必学的Java基础知识(1)----反射(转)
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...
- 学习Spring必学的Java基础知识(1)----反射
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...
- java基础知识一览(二)
一.java基础知识 1.一个文件中只能有一个public的类,因为他的类名要求和文件名相同. 2.classpath变量可以设置其它目录下的类. 例如:类文件所在目录是:F:\Javajdk,那么没 ...
- Java基础知识(壹)
写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...
- java基础知识小总结【转】
java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...
- Java基础知识系列——String
最近晚上没有什么事(主要是不加班有单身),就复习了一下Java的基础知识.我复习Java基础知识主要是依据Java API和The Java™ Tutorials. 今天是第一篇,复习了一下Strin ...
- 学习android学习必备的java基础知识--四大内部类
学习android必备的java基础知识--四大内部类 今天学习android课程,因为我的主专业是JAVA,但是兴趣班却有这其他专业的同学,学习android 需要具备一些java的基础知识,因此就 ...
- Java基础之理解Annotation(与@有关,即是注释)
Java基础之理解Annotation 一.概念 Annontation是Java5开始引入的新特征.中文名称一般叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata) ...
- JAVA基础知识之网络编程——-网络基础(Java的http get和post请求,多线程下载)
本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息.URL和URLConnect可以用来访问web ...
随机推荐
- Week 1:2015/4/27~2015/5/3
Update everyday.(Last edit:4/30 01:00) Task 1:TPO X 2.5(finish 1,then finish 2 more) Task 2:TC Tarja ...
- 第三篇:白话tornado源码之请求来了
上一篇<白话tornado源码之待请求阶段>中介绍了tornado框架在客户端请求之前所做的准备(下图1.2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未 ...
- sed 技巧
八.流编辑器sed sed ':a;N;$!ba;s/0.01/0.0001/g' file:a 创建一个labelaN 将下一行读入到模式空间$! 如果不是最后一行,ba跳转到label a处s/0 ...
- 【CSS 杂记】
1.CSS达到截取效果 地方卡机了会计师的立法及 => 地方卡机了... max-width: 400px; overflow: hidden; white-space: nowrap; t ...
- apache on centos
httpd https://www.centos.org/docs/5/html/Deployment_Guide-en-US/s1-apache-startstop.html
- List转换成XML
protected void Button1_Click(object sender, EventArgs e) { var customerlist = CustomerHelper.GetList ...
- javascript 函数重载 overloading
函数重载 https://en.wikipedia.org/wiki/Function_overloading In some programming languages, function over ...
- 偶遇到 java.util.ConcurrentModificationException 的异常
今天在调试程序 遇到了如此问题 贴上代码来看看稍后分析 List<String> list = null;boolean isUpdate = false;try { list = JSO ...
- C/C++ 结构体 指针 函数传递
#include <stdio.h> #include <stdlib.h> struct student{ int num; ]; double dec; }; void s ...
- android Dialog重绘
String title = ""; if(itemInfo!=null) title = "\n\""+itemInfo.itemSSID+&quo ...