重温java从入门到精通(第2版)- 4

重温java从入门到精通(第2版)- 4

  1. 定义一个注解的形式
@interface MyAnnotation{
	public String key() default "language";
	public String value() default "java";
}

如果key没有被初始化,那么注解的时候必须提供值,类似

@myAnnotation(key="...")

自定义注解上@Documented有注解的作用,将自定义注解设置为文档说明信息。
@Retention(RetentionPolicy.RUNTIME)
RetentionPolicy是一个枚举类型,用于指定Annotation的保存范围。RetentionPolicy包含3个取值范围:
⑴ SOURCE : 此Annotation类型的信息只会记录在源文件中,编译时将被编译器丢弃,及此Annotation信息不会保存在编译好的类文件中。
⑵ CLASS : 编译器将把注释记录在类文件中,但不会被加载到JVM中。如果一个Annotation声明时没有指定范围,则系统默认值是CLASS。
⑶ RUNTIME : 此Annotation类型的信息将会保留在源文件、类文件中,在执行时也会加载到Java虚拟机(JVM)中,因此可以反射性地读取。
前面章节的3个内建的Annotation的保存范围分别为:
⑴ Override定义采用的是@Retention( value = SOURCE ),注解信息只能在源文件中出现。
⑵ Deprecated定义采用的是@Retention( value = RUNTIME ),注解信息在执行时出现。
⑶ SuppressWarnings定义采用的是@Retention( value = SOURCE ), 注解信息只能在源文件中出现。

  1. 注解若想发挥更大作用,还需借反射机制之力。通过反射,可以取得在一个方法上声明的注解的全部内容。只有定义采用的是@Retention( value = RUNTIME )的Annotation才能在程序运行时被反射机制取得。
Class<> cls = Class.forName("classname");
Method method = cls.getMethod("methodname");
MyAnnotation ma = method.getAnnotation(MyAnnotation.class)
System.out.Println(ma.key() + "->" + ma.value());
  1. @Target Annotation明确地指出了一个Annotation的使用位置。在@Target Annotation中存在一个ElementType[] 枚举类型的变量,这个变量主要用于指定Annotation的使用限制。ElementType类定义了下面8个取值。
    ⑴ ANNOTATION_TYPE : 只能用在注释上;
    ⑵ CONSIRUCTOR : 只能用在构造方法的声明上;
    ⑶ FOELD : 只能用在字段的声明(包括枚举常量)上;
    ⑷ LOCAL_VARIABLE : 只能用在局部变量的声明上;
    ⑸ METHOD : 只能用在方法的声明上;
    ⑹ PACKAGE : 只能用在包的声明上;
    ⑺ PARAMEIER : 只能用在参数的声明上;
    ⑻ TYPE : 只能用在类、接口、枚举类型上。

  2. @Inherited用于标注一个父类的Annotation是否可以被子类继承,如果一个Annotation需要被其子类所继承,则在声明时直接使用@Inherited注释即可。如果没有写上此注释,则此Annotation无法被继承的。

  3. 线程的一些操作方法

方法名称方法描述
public static int activeCount()返回线程组中目前活动的线程数目
public static Thread currentThread()返回当前正在执行的线程的引用
public static int enumerate(Thread[] tarray)将当前和子线程组中的活动线程复制到指定的线程数组
public final String getName()返回线程名称
public final int getPriority()返回线程的优先级
public final ThreadGroup getThreadGroup()返回线程的线程组
public static boolean interrupted()判断目前线程是否被中断
public final boolean isAlive()判断线程是否在活动
public boolean isInterrupted()判断线程是否被中断
public final void join() throws InterruptedException等待该线程死亡,直到该线程结束了才往下继续执行,也就是说把两个交替执行的线程合并为顺序执行的线程
public final synchronized void join(long millis) throws InterruptedException等待该线程终止的事件最长为millis毫秒,也就是说如果该线程在millis毫秒后还没有结束,就不再等待,直接向下执行。
public final synchronized void join(long millis,int nanos) throws InterruptedException等待该线程终止的事件最长为millis毫秒+nanos纳秒
public void run()执行线程
public void setName(String name)设置线程名称
public void setPriority(int newPriority)设置线程的优先级
public static native void sleep(long millis) throws InterruptedException使目前正在执行的线程休眠millis毫秒
public synchronized void start()开始执行线程
  1. 区分Thread中的start()和run()方法的联系和不同。
    ⑴ start()方法。它的作用是启动一个新线程,有了它的调用,才能真正实现多线程运行,这时无需等待run方法体代码执行完毕,而是直接继续执行start()其后的代码。读者可以这样理解,start()的调用,使得主线程“兵分两路”——创建了一个新线程,并使得这个线程进入“就绪状态”。 “就绪状态”其实就是“万事俱备,只欠CPU”。。如果主线程执行完start()语句后,它的CPU时间片还没有用完,那么它就会很自然的接着运行start()后面的语句。一旦新的线程获得CPU时间片,就开始执行run()方法,这里run()方法称为线程体,它包含了这个线程要执行的内容,一旦run()方法运行结束,那么此线程随即终止。此外,要注意start()不能被重复调用。调用了多次start(),除了得到一个异常中断外,并没有多创建新的线程。
    ⑵ run()方法。run()方法只是类的一个普通方法而已,如果直接调用run()方法,程序中依然只有主线程这一个线程,其程序执行路径依然只有一条,也就是说,一旦run()方法被调用,程序还要顺序执行,只有run()方法体执行完毕后,才可继续执行其后的代码,这样并没有达到多线程并发执行的目的。由于run()方法和普通的成员方法一样,所以,很自然地,它可以被重复调用多次。每次单独调用run(),就会在当前线程中执行run(),而并不会启动新线程。

  2. 在Java多线程编程中,经常会遇到需要中止线程的情况。例如,启动多个线程在数据库中搜索,如果有一个线程返回了需要的搜索结果,则其他线程就可以取消了。在实施中断线程过程中,有三个函数比较常用的成员方法。
    ⑴ Thread.interrupt():来设置中断状态为true,当一个线程运行时,另一个线程可以调用另外一个线程对应的interrupt()方法来中断它。
    ⑵ Thread.isInterrupted():来获取线程的中断状态。
    ⑶ Thread.interrupted():这是一个静态方法,用来获取中断状态(),并清除中断状态,其获取的是清除之前的值,也就是说连续两次调用此方法,第二次一定会返回false。
    调用interrupt()方法并不会使正在执行的线程停止执行,它只对调用wait、join、sleep等方法或由于I/O操作等原因受阻的线程产生影响,使其退出暂停执行的状态

  3. Java是通过Object类的wait()、notify ()、notifyAll ()这几个方法来实现线程间的通信的,又因为所有的类都是从Object继承的,因此任何类都可以直接使用这些方法。下面是这3个方法的简要说明。
    wait():通知当前线程进入睡眠状态,直到其他线程进入并调用notify()或notifyAll()为止。在当前线程睡眠之前,该线程会释放所占有的“锁标志”,即其占有的所有synchronized标识的代码块可被其他线程使用。
    notify():唤醒在该同步代码块中第1个调用wait()的线程。这类似排队买票,一个人买完之后,后面的人才可以继续买。
    notifyAll():唤醒该同步代码块中所有调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。
    wait()、notify()、notifyAll()这3个方法只能在synchronized方法中调用,即无论线程调用的是wait()还是notify()方法,该线程必须先得到该对象的所有权。这样,notify()就只能唤醒同一对象监视器中调用wait()的线程。而使用多个对象监视器,就可以分别有多个wait()、notify()的情况,同组里的wait()只能被同组的notify()唤醒。

  4. 流序列中的数据通常有两种形式:文本流和二进制流。
    文本流每一个字节存放一个ASCII码,代表一个字符(而对于Unicode编码来说,每两个字节表示一个字符)。使用文本流时,可能会发生一些字符转换。例如,在Windows操作系统中,当输出换行字符的时候,它可以被转换为回车和换行序列。
    二进制流,也称字节流,它是把数据按其内存中存储的以字节形式“原封不动”地输出或存储。两者的区别与联系可以用下面的例子(以ASCII码为例)来说明。例如,有一个整型数12345,其在内存当中仅需要2个字节,由于系统为整型数据分配4个字节,所以其高位两个字节均为0,而按文本流形式输出则占用5个字节,分别是“12345”这5个字符对应的ASCII码

  5. File类只能对文件进行一些简单操作,如读取文件的属性以及创建、删除和更名等,但并不支持文件内容的读/写。如果想对文件进行实施读写操作,就必须通过输入/输出流来达到这一目的。

  6. 除了File类之外,Java还提供了专门处理文件的类,即RandomAccessFile(随机访问文件)类。该类是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。RandomAccessFile类支持“随机访问”方式,这里“随机”是指可以跳转到文件的任意位置处读写数据。在访问一个文件的时候,不必把文件从头读到尾,而是希望像访问一个数据库一样“随心所欲”地访问一个文件的某个部分,这时使用RandomAccessFile类就是最佳选择。RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当读写n个字节后,文件指示器将指向这n个字节后面的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。RandomAccessFile类在数据等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但该类仅限于操作文件,不能访问其他的IO设备,如网络、内存映像等

  7. Java 的流式输入/输出建立在4个抽象类的基础上:InputStream、OutputStream、Reader和Writer。
    InputStream 和OutputStream被设计成字节流类,而Reader 和Writer 则被设计成字符流类。
    ⑴ 字节输入流变为字符输入流:InputStreamReader;
    ⑵ 字节输出流变为字符输出流:OutputStreamWriter。
    为了达到较高的转换效率,避免频繁地进行字符与字节间的相互转换,建议最好不要直接使用这两个类来进行读写,而应尽量使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader类。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值