精华内容
下载资源
问答
  • Java知识点总结归纳

    2017-07-18 15:05:59
    Java知识点总结归纳 Java工程师-搁浅 12 分钟前 流 Java所有的流类位于http://java.io包中,都分别继承字以下四种抽象流类型。 继承自InputStream/OutputStream的流都是用于向程序中输入/...


    Java知识点总结归纳

    Java知识点总结归纳

    Java工程师-搁浅Java工程师-搁浅
    12 分钟前

    Java所有的流类位于java.io包中,都分别继承字以下四种抽象流类型。


    继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。
    继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。

    异常


    Java的异常(包括ExceptionError)分为:

    • 可查的异常(checked exceptions)
    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
    • 不可查的异常(unchecked exceptions)
    包括运行时异常(RuntimeException与其子类)和错误(Error)。

    运行时异常和非运行时异常:

    • RuntimeException
    NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
    • RuntimeException以外的Exception
    从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

    注解

    Java SE5内置了三种标准注解:

    @Override,表示当前的方法定义将覆盖超类中的方法。
    
     @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。
    
     @SuppressWarnings,关闭不当编译器警告信息。
    

    Java还提供了4中注解,专门负责新注解的创建:

    • @Target:
    表示该注解可以用于什么地方,可能的ElementType参数有: CONSTRUCTOR:构造器的声明 FIELD:域声明(包括enum实例) LOCAL_VARIABLE:局部变量声明 METHOD:方法声明 PACKAGE:包声明 PARAMETER:参数声明 TYPE:类、接口(包括注解类型)或enum声明
    • @Retention
    表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括: SOURCE:注解将被编译器丢弃 CLASS:注解在class文件中可用,但会被VM丢弃 RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息
    • @Document
    将注解包含在Javadoc中
    • @Inherited
    允许子类继承父类中的注解

    Example

    定义注解:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UseCase {
        public String id();
        public String description() default "no description";
    }
    

    使用注解:

    public class PasswordUtils {
         @UseCase(id = 47, description = "Passwords must contain at least one numeric")
         public boolean validatePassword(String password) {
             return (password.matches("\\w*\\d\\w*"));
         }
     
         @UseCase(id = 48)
         public String encryptPassword(String password) {
             return new StringBuilder(password).reverse().toString();
         }
     }
    

    解析注解:

    public static void main(String[] args) {
         List<Integer> useCases = new ArrayList<Integer>();
         Collections.addAll(useCases, 47, 48, 49, 50);
         trackUseCases(useCases, PasswordUtils.class);
     }
     
     public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
         for (Method m : cl.getDeclaredMethods()) {
             UseCase uc = m.getAnnotation(UseCase.class);
             if (uc != null) {
                 System.out.println("Found Use Case:" + uc.id() + " "
                             + uc.description());
                 useCases.remove(new Integer(uc.id()));
             }
         }
         for (int i : useCases) {
             System.out.println("Warning: Missing use case-" + i);
         }
     }
     // Found Use Case:47 Passwords must contain at least one numeric
     // Found Use Case:48 no description
     // Warning: Missing use case-49
     // Warning: Missing use case-50
    

    安全性

    1. 严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。
    2. 无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。
    3. 数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。
    4. 强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException
    5. 语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。
    6. 垃圾回收。
    7. Exception。

    类加载

    原理

    ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

    当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

    如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

    JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。

    加载器

    1. BootStrap ClassLoader
    启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。
      URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
       for (int i = 0; i < urls.length; i++) {
           System.out.println(urls[i].toExternalForm());  
       }
       // 也可以通过sun.boot.class.path获取
       System.out.println(System.getProperty("sun.boot.class.path"))
    
    1. Extension ClassLoader
    扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
    1. App ClassLoader
    系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

    注意

    除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。
    

    关键字

    strictfp(strict float point)

    strictfp 关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。

    如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。

    transiant

    变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

    volatile

    作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。

    final

    1. 修饰基础数据成员(as const)
    2. 修饰类或对象的引用
    3. 修饰方法的final(cannot overwrite)
    4. 修饰类或者参数


    初始化

    父静态->子静态 父变量->父初始化区->父构造 子变量->子初始化区->子构造

    多线程

    JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

    线程池

    concurrent下的线程池

    newSingleThreadExecutorExecutors

    创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
    1. newFixedThreadPool
    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
    1. newCachedThreadPool
    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
    1. newScheduledThreadPool
    创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

    线程安全

    线程安全是一个很大的问题,Java 最常见的 HttpServlet 就是单实例多线程,解决这样的问题,有多种方式:

    1. ThreadLocal

    ThreadLocal 看下一节的内存图就很好理解,每个线程都有自己的工作内存,ThreadLocal 就是将变量存到线程自己的工作内存中,所以不会有并发问题。

    1. Synchronized synchronized锁住的是括号里的对象,而不是代码。对于非 static 的 synchronized 方法,锁的就是对象本身也就是 this。该关键字可以加到:
    • 实例方法
    • 静态方法
    • 实例方法中的同步块
    • 静态方法中的同步块


    1. ReentrantLock / Condition synchronized 不够灵活,例如读写文件,读和读之间不应该互斥,这个时候就可以使用 ReentrantLock 增加并发能力。Condition 是绑定到 Lock 上的,可以用于线程间通信,例如这个面试题,就可以使用 Condition 唤起线程写自己的name 。

    有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:A:1 2 3 4 1 2.... B:2 3 4 1 2 3.... C:3 4 1 2 3 4.... D:4 1 2 3 4 1....

    1. 并发容器 常见的 ConcurrentHashMap CopyOnWriteArrayList 用于多线程下存放数据,Queue BlockingQueue 用于排队消费。
    2. Atomic 包在 Atomic 包里一共有 12 个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。某些并发问题,需要无锁解决时,就可以考虑使用原子方法。

    内存模型

    Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的 工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

    如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,首先是定义了8种原子操作:

    • lock:将主内存中的变量锁定,为一个线程所独占
    • unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量
    • read:将主内存中的变量值读到工作内存当中
    • load:将read读取的值保存到工作内存中的变量副本中。
    • use:将值传递给线程的代码执行引擎
    • assign:将执行引擎处理返回的值重新赋值给变量副本
    • store:将变量副本的值存储到主内存中。
    • write:将store存储的值写入到主内存的共享变量当中。

    内存组成

    堆(Heap)

    运行时数据区域,所有类实例和数组的内存均从此处分配。Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。

    • News Generation(Young Generation即图中的Eden + From Space + To Space)
      • Eden 存放新生的对象
      • Survivor Space 两个 存放每次垃圾回收后存活的对象


    • Old Generation(Tenured Generation 即图中的Old Space) 主要存放应用程序中生命周期长的存活对象

    非堆内存

    JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。

    • Permanent Generation (图中的Permanent Space)存放JVM自己的反射对象,比如类对象和方法对象
    • native heap
    还没有评论
    评论由作者筛选后显示

    Java知识点总结归纳

    Java知识点总结归纳

    Java工程师-搁浅Java工程师-搁浅
    12 分钟前

    Java所有的流类位于java.io包中,都分别继承字以下四种抽象流类型。


    继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。
    继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。

    异常


    Java的异常(包括ExceptionError)分为:

    • 可查的异常(checked exceptions)
    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
    • 不可查的异常(unchecked exceptions)
    包括运行时异常(RuntimeException与其子类)和错误(Error)。

    运行时异常和非运行时异常:

    • RuntimeException
    NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
    • RuntimeException以外的Exception
    从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

    注解

    Java SE5内置了三种标准注解:

    @Override,表示当前的方法定义将覆盖超类中的方法。
    
     @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。
    
     @SuppressWarnings,关闭不当编译器警告信息。
    

    Java还提供了4中注解,专门负责新注解的创建:

    • @Target:
    表示该注解可以用于什么地方,可能的ElementType参数有: CONSTRUCTOR:构造器的声明 FIELD:域声明(包括enum实例) LOCAL_VARIABLE:局部变量声明 METHOD:方法声明 PACKAGE:包声明 PARAMETER:参数声明 TYPE:类、接口(包括注解类型)或enum声明
    • @Retention
    表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括: SOURCE:注解将被编译器丢弃 CLASS:注解在class文件中可用,但会被VM丢弃 RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息
    • @Document
    将注解包含在Javadoc中
    • @Inherited
    允许子类继承父类中的注解

    Example

    定义注解:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UseCase {
        public String id();
        public String description() default "no description";
    }
    

    使用注解:

    public class PasswordUtils {
         @UseCase(id = 47, description = "Passwords must contain at least one numeric")
         public boolean validatePassword(String password) {
             return (password.matches("\\w*\\d\\w*"));
         }
     
         @UseCase(id = 48)
         public String encryptPassword(String password) {
             return new StringBuilder(password).reverse().toString();
         }
     }
    

    解析注解:

    public static void main(String[] args) {
         List<Integer> useCases = new ArrayList<Integer>();
         Collections.addAll(useCases, 47, 48, 49, 50);
         trackUseCases(useCases, PasswordUtils.class);
     }
     
     public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
         for (Method m : cl.getDeclaredMethods()) {
             UseCase uc = m.getAnnotation(UseCase.class);
             if (uc != null) {
                 System.out.println("Found Use Case:" + uc.id() + " "
                             + uc.description());
                 useCases.remove(new Integer(uc.id()));
             }
         }
         for (int i : useCases) {
             System.out.println("Warning: Missing use case-" + i);
         }
     }
     // Found Use Case:47 Passwords must contain at least one numeric
     // Found Use Case:48 no description
     // Warning: Missing use case-49
     // Warning: Missing use case-50
    

    安全性

    1. 严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。
    2. 无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。
    3. 数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。
    4. 强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException
    5. 语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。
    6. 垃圾回收。
    7. Exception。

    类加载

    原理

    ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

    当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

    如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

    JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。

    加载器

    1. BootStrap ClassLoader
    启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。
      URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
       for (int i = 0; i < urls.length; i++) {
           System.out.println(urls[i].toExternalForm());  
       }
       // 也可以通过sun.boot.class.path获取
       System.out.println(System.getProperty("sun.boot.class.path"))
    
    1. Extension ClassLoader
    扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
    1. App ClassLoader
    系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

    注意

    除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。
    

    关键字

    strictfp(strict float point)

    strictfp 关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。

    如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。

    transiant

    变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

    volatile

    作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。

    final

    1. 修饰基础数据成员(as const)
    2. 修饰类或对象的引用
    3. 修饰方法的final(cannot overwrite)
    4. 修饰类或者参数


    初始化

    父静态->子静态 父变量->父初始化区->父构造 子变量->子初始化区->子构造

    多线程

    JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

    线程池

    concurrent下的线程池

    newSingleThreadExecutorExecutors

    创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
    1. newFixedThreadPool
    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
    1. newCachedThreadPool
    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
    1. newScheduledThreadPool
    创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

    线程安全

    线程安全是一个很大的问题,Java 最常见的 HttpServlet 就是单实例多线程,解决这样的问题,有多种方式:

    1. ThreadLocal

    ThreadLocal 看下一节的内存图就很好理解,每个线程都有自己的工作内存,ThreadLocal 就是将变量存到线程自己的工作内存中,所以不会有并发问题。

    1. Synchronized synchronized锁住的是括号里的对象,而不是代码。对于非 static 的 synchronized 方法,锁的就是对象本身也就是 this。该关键字可以加到:
    • 实例方法
    • 静态方法
    • 实例方法中的同步块
    • 静态方法中的同步块


    1. ReentrantLock / Condition synchronized 不够灵活,例如读写文件,读和读之间不应该互斥,这个时候就可以使用 ReentrantLock 增加并发能力。Condition 是绑定到 Lock 上的,可以用于线程间通信,例如这个面试题,就可以使用 Condition 唤起线程写自己的name 。

    有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:A:1 2 3 4 1 2.... B:2 3 4 1 2 3.... C:3 4 1 2 3 4.... D:4 1 2 3 4 1....

    1. 并发容器 常见的 ConcurrentHashMap CopyOnWriteArrayList 用于多线程下存放数据,Queue BlockingQueue 用于排队消费。
    2. Atomic 包在 Atomic 包里一共有 12 个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。某些并发问题,需要无锁解决时,就可以考虑使用原子方法。

    内存模型

    Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的 工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

    如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,首先是定义了8种原子操作:

    • lock:将主内存中的变量锁定,为一个线程所独占
    • unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量
    • read:将主内存中的变量值读到工作内存当中
    • load:将read读取的值保存到工作内存中的变量副本中。
    • use:将值传递给线程的代码执行引擎
    • assign:将执行引擎处理返回的值重新赋值给变量副本
    • store:将变量副本的值存储到主内存中。
    • write:将store存储的值写入到主内存的共享变量当中。

    内存组成

    堆(Heap)

    运行时数据区域,所有类实例和数组的内存均从此处分配。Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。

    • News Generation(Young Generation即图中的Eden + From Space + To Space)
      • Eden 存放新生的对象
      • Survivor Space 两个 存放每次垃圾回收后存活的对象


    • Old Generation(Tenured Generation 即图中的Old Space) 主要存放应用程序中生命周期长的存活对象

    非堆内存

    JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。

    • Permanent Generation (图中的Permanent Space)存放JVM自己的反射对象,比如类对象和方法对象
    • native heap
    还没有评论
    评论由作者筛选后显示

    展开全文
  • Java所有的流类位于http://java.io包中,都分别继承字以下四种抽象流类型。继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节...异常Java的异常(包括Exception和Error)分为...

    Java所有的流类位于http://java.io包中,都分别继承字以下四种抽象流类型。继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。

    继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。

    异常

    Java的异常(包括Exception和Error)分为:可查的异常(checked exceptions)除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。不可查的异常(unchecked exceptions)包括运行时异常(RuntimeException与其子类)和错误(Error)。

    运行时异常和非运行时异常:RuntimeExceptionNullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。RuntimeException以外的Exception从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

    注解

    Java SE5内置了三种标准注解:

    @Override,表示当前的方法定义将覆盖超类中的方法。

    @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。

    @SuppressWarnings,关闭不当编译器警告信息。

    Java还提供了4中注解,专门负责新注解的创建:@Target:表示该注解可以用于什么地方,可能的ElementType参数有:

    CONSTRUCTOR:构造器的声明

    FIELD:域声明(包括enum实例)

    LOCAL_VARIABLE:局部变量声明

    METHOD:方法声明

    PACKAGE:包声明

    PARAMETER:参数声明

    TYPE:类、接口(包括注解类型)或enum声明@Retention表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

    SOURCE:注解将被编译器丢弃

    CLASS:注解在class文件中可用,但会被VM丢弃

    RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息@Document将注解包含在Javadoc中@Inherited允许子类继承父类中的注解

    Example

    定义注解:

    @Target(ElementType.METHOD)

    @Retention(RetentionPolicy.RUNTIME)

    public @interface UseCase {

    public String id();

    public String description() default "no description";

    }

    使用注解:

    public class PasswordUtils {

    @UseCase(id = 47, description = "Passwords must contain at least one numeric")

    public boolean validatePassword(String password) {

    return (password.matches("\\w*\\d\\w*"));

    }

    @UseCase(id = 48)

    public String encryptPassword(String password) {

    return new StringBuilder(password).reverse().toString();

    }

    }

    解析注解:

    public static void main(String[] args) {

    List useCases = new ArrayList();

    Collections.addAll(useCases, 47, 48, 49, 50);

    trackUseCases(useCases, PasswordUtils.class);

    }

    public static void trackUseCases(List useCases, Class> cl) {

    for (Method m : cl.getDeclaredMethods()) {

    UseCase uc = m.getAnnotation(UseCase.class);

    if (uc != null) {

    System.out.println("Found Use Case:" + uc.id() + " "

    + uc.description());

    useCases.remove(new Integer(uc.id()));

    }

    }

    for (int i : useCases) {

    System.out.println("Warning: Missing use case-" + i);

    }

    }

    // Found Use Case:47 Passwords must contain at least one numeric

    // Found Use Case:48 no description

    // Warning: Missing use case-49

    // Warning: Missing use case-50

    安全性严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。

    无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。

    数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。

    强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException

    语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。

    垃圾回收。

    Exception。

    类加载

    原理

    ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

    当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

    如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。

    加载器BootStrap ClassLoader启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。

    URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();

    for (int i = 0; i < urls.length; i++) {

    System.out.println(urls[i].toExternalForm());

    }

    // 也可以通过sun.boot.class.path获取

    System.out.println(System.getProperty("sun.boot.class.path"))Extension ClassLoader扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。App ClassLoader系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

    注意:

    除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。

    关键字

    strictfp(strict float point)strictfp 关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。

    如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。

    transiant变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

    volatile作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。

    final修饰基础数据成员(as const)

    修饰类或对象的引用

    修饰方法的final(cannot overwrite)

    修饰类或者参数

    初始化父静态->子静态

    父变量->父初始化区->父构造

    子变量->子初始化区->子构造

    多线程

    JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

    线程池

    concurrent下的线程池:

    newSingleThreadExecutorExecutors创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。newFixedThreadPool创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。newCachedThreadPool创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。newScheduledThreadPool创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

    线程安全

    线程安全是一个很大的问题,Java 最常见的 HttpServlet 就是单实例多线程,解决这样的问题,有多种方式:ThreadLocal

    ThreadLocal 看下一节的内存图就很好理解,每个线程都有自己的工作内存,ThreadLocal 就是将变量存到线程自己的工作内存中,所以不会有并发问题。

    Synchronized

    synchronized锁住的是括号里的对象,而不是代码。对于非 static 的 synchronized 方法,锁的就是对象本身也就是 this。该关键字可以加到:实例方法

    静态方法

    实例方法中的同步块

    静态方法中的同步块

    ReentrantLock / Condition

    synchronized 不够灵活,例如读写文件,读和读之间不应该互斥,这个时候就可以使用 ReentrantLock 增加并发能力。Condition 是绑定到 Lock 上的,可以用于线程间通信,例如这个面试题,就可以使用 Condition 唤起线程写自己的name 。有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:A:1 2 3 4 1 2.... B:2 3 4 1 2 3.... C:3 4 1 2 3 4.... D:4 1 2 3 4 1....

    并发容器

    常见的 ConcurrentHashMap CopyOnWriteArrayList 用于多线程下存放数据,Queue BlockingQueue 用于排队消费。

    Atomic 包在 Atomic 包里一共有 12 个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。某些并发问题,需要无锁解决时,就可以考虑使用原子方法。

    内存模型

    Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的 工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

    如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,首先是定义了8种原子操作:lock:将主内存中的变量锁定,为一个线程所独占

    unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量

    read:将主内存中的变量值读到工作内存当中

    load:将read读取的值保存到工作内存中的变量副本中。

    use:将值传递给线程的代码执行引擎

    assign:将执行引擎处理返回的值重新赋值给变量副本

    store:将变量副本的值存储到主内存中。

    write:将store存储的值写入到主内存的共享变量当中。

    内存组成

    堆(Heap)

    运行时数据区域,所有类实例和数组的内存均从此处分配。Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。News Generation(Young Generation即图中的Eden + From Space + To Space)Eden 存放新生的对象

    Survivor Space 两个 存放每次垃圾回收后存活的对象

    Old Generation(Tenured Generation 即图中的Old Space) 主要存放应用程序中生命周期长的存活对象

    非堆内存

    JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。Permanent Generation (图中的Permanent Space)存放JVM自己的反射对象,比如类对象和方法对象

    native heap

    展开全文
  • Java所有的流类位于http://java.io包中,都分别继承字以下四种抽象流类型。 继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。 继承自Reader/Writer的流都是...

    一、流

    Java所有的流类位于http://java.io包中,都分别继承字以下四种抽象流类型。

    继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。

    继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。

    二、异常

    Java的异常(包括ExceptionError)分为:

    • 可查的异常(checked exceptions)

    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

    • 不可查的异常(unchecked exceptions)

    包括运行时异常(RuntimeException与其子类)和错误(Error)。

    运行时异常和非运行时异常:

    • RuntimeException

    NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

    • RuntimeException以外的Exception

    从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

    三、注解

    Java SE5内置了三种标准注解:

     @Override,表示当前的方法定义将覆盖超类中的方法。
    
     @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。
    
     @SuppressWarnings,关闭不当编译器警告信息。
    
    

    Java还提供了4中注解,专门负责新注解的创建:

    • @Target:

    表示该注解可以用于什么地方,可能的ElementType参数有:
    CONSTRUCTOR:构造器的声明
    FIELD:域声明(包括enum实例)
    LOCAL_VARIABLE:局部变量声明
    METHOD:方法声明
    PACKAGE:包声明
    PARAMETER:参数声明
    TYPE:类、接口(包括注解类型)或enum声明

    • @Retention

    表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
    SOURCE:注解将被编译器丢弃
    CLASS:注解在class文件中可用,但会被VM丢弃
    RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息

    • @Document

    将注解包含在Javadoc中

    • @Inherited

    允许子类继承父类中的注解

    Example

    定义注解:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UseCase {
        public String id();
        public String description() default "no description";
    }
    

    使用注解:

    public class PasswordUtils {
         @UseCase(id = 47, description = "Passwords must contain at least one numeric")
         public boolean validatePassword(String password) {
             return (password.matches("\\w*\\d\\w*"));
         }
    
         @UseCase(id = 48)
         public String encryptPassword(String password) {
             return new StringBuilder(password).reverse().toString();
         }
     }
    

    解析注解:

    public static void main(String[] args) {
         List<Integer> useCases = new ArrayList<Integer>();
         Collections.addAll(useCases, 47, 48, 49, 50);
         trackUseCases(useCases, PasswordUtils.class);
     }
    
     public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
         for (Method m : cl.getDeclaredMethods()) {
             UseCase uc = m.getAnnotation(UseCase.class);
             if (uc != null) {
                 System.out.println("Found Use Case:" + uc.id() + " "
                             + uc.description());
                 useCases.remove(new Integer(uc.id()));
             }
         }
         for (int i : useCases) {
             System.out.println("Warning: Missing use case-" + i);
         }
     }
     // Found Use Case:47 Passwords must contain at least one numeric
     // Found Use Case:48 no description
     // Warning: Missing use case-49
     // Warning: Missing use case-50
    

    四、安全性

    1. 严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。

    2. 无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。

    3. 数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。

    4. 强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException

    5. 语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。

    6. 垃圾回收。

    7. Exception。

    五、类加载

    1. 原理

    ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

    当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

    如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

    JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。

    2. 加载器

    1. BootStrap ClassLoader

    启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。

       URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
       for (int i = 0; i < urls.length; i++) {
           System.out.println(urls[i].toExternalForm());  
       }
       // 也可以通过sun.boot.class.path获取
       System.out.println(System.getProperty("sun.boot.class.path"))
    
    1. Extension ClassLoader

    扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。

    1. App ClassLoader

    系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

    注意

    除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。
    

    六、关键字

    strictfp(strict float point)

    strictfp 关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。

    如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。

    transiant

    变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

    volatile

    作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。

    final

    1. 修饰基础数据成员(as const)

    2. 修饰类或对象的引用

    3. 修饰方法的final(cannot overwrite)

    4. 修饰类或者参数

    七、初始化

    父静态->子静态
    父变量->父初始化区->父构造
    子变量->子初始化区->子构造

    八、多线程

    JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

    1. 线程池

    concurrent下的线程池

    newSingleThreadExecutorExecutors

    创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

    1. newFixedThreadPool

    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

    1. newCachedThreadPool

    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

    1. newScheduledThreadPool

    创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

    2. 线程安全

    线程安全是一个很大的问题,Java 最常见的 HttpServlet 就是单实例多线程,解决这样的问题,有多种方式:

    1. ThreadLocal

      ThreadLocal 看下一节的内存图就很好理解,每个线程都有自己的工作内存,ThreadLocal 就是将变量存到线程自己的工作内存中,所以不会有并发问题。

    2. Synchronized
      synchronized锁住的是括号里的对象,而不是代码。对于非 static 的 synchronized 方法,锁的就是对象本身也就是 this。该关键字可以加到:

      • 实例方法

      • 静态方法

      • 实例方法中的同步块

      • 静态方法中的同步块

    3. ReentrantLock / Condition
      synchronized 不够灵活,例如读写文件,读和读之间不应该互斥,这个时候就可以使用 ReentrantLock 增加并发能力。Condition 是绑定到 Lock 上的,可以用于线程间通信,例如这个面试题,就可以使用 Condition 唤起线程写自己的name 。

      有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推…现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:A:1 2 3 4 1 2… B:2 3 4 1 2 3… C:3 4 1 2 3 4… D:4 1 2 3 4 1…

    4. 并发容器
      常见的 ConcurrentHashMap CopyOnWriteArrayList 用于多线程下存放数据,Queue BlockingQueue 用于排队消费。

    5. Atomic 包在 Atomic 包里一共有 12 个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。某些并发问题,需要无锁解决时,就可以考虑使用原子方法。

    九、内存模型

    Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的 工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

    如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,首先是定义了8种原子操作:

    • lock:将主内存中的变量锁定,为一个线程所独占

    • unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量

    • read:将主内存中的变量值读到工作内存当中

    • load:将read读取的值保存到工作内存中的变量副本中。

    • use:将值传递给线程的代码执行引擎

    • assign:将执行引擎处理返回的值重新赋值给变量副本

    • store:将变量副本的值存储到主内存中。

    • write:将store存储的值写入到主内存的共享变量当中。

    内存组成

    堆(Heap)

    运行时数据区域,所有类实例和数组的内存均从此处分配。Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器 的自动内存管理系统回收。

    • News Generation(Young Generation即图中的Eden + From Space + To Space)

      • Eden 存放新生的对象

      • Survivor Space 两个 存放每次垃圾回收后存活的对象

    • Old Generation(Tenured Generation 即图中的Old Space) 主要存放应用程序中生命周期长的存活对象

    非堆内存

    JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。

    • Permanent Generation (图中的Permanent Space)存放JVM自己的反射对象,比如类对象和方法对象

    • native heap

    十、写到最后

    如果觉得本文对你有帮助的话,请你也不要吝啬你的赞,你们的支持是对我最大的鼓励。今天的Java知识分享就到这里!点关注,不迷路,关注程序员曾曾,每天分享不同的Java基础知识,想要知道更多Java基础知识的我这边整理了一个我自己的GitHub仓库:Java小白修炼手册,大家如果有需要可以自行查看

    展开全文
  • 1. 基本数据类型整形:byte 1 个字节short 2 个字节int 4个字节long 8个字节字符:char 2个字节浮点数:float 4个字节double 8个字节布尔:boolean 1个字节2.java 7 新增二进制整数以0b或者0B开头3.java中字符时16位...

    1. 基本数据类型

    整形:

    byte      1 个字节

    short     2 个字节

    int          4个字节

    long       8个字节

    字符:

    char     2个字节

    浮点数:

    float       4个字节

    double   8个字节

    布尔:

    boolean   1个字节

    2.java 7  新增二进制整数

    以0b或者0B开头

    3.java中字符时16位的Unicode编码方式,格式是'\uXXXX',其中xxxx代表一个十六进制整数

    4.java中规定了正无穷大、负无穷大和零

    正无穷大=  一个正数除以0

    负无穷大= 一个负数除以零

    0.0 除以0.0  或者 对一个负数开方  得到一个非数

    5. 在java中布尔类型只能是true和false

    6. 在java中没有多维数组

    看似像C语言中的多维数组不是真正的数组,比如 a[3][4] , a[0] a[1] a[2]  是真实存在的,装的是地址,和c语言中动态分配为的数组一样

    int  [][]  b  = new  int[3][4]

    7. Java中带包的编译方法

    javac -d .  Hello.java    会在当前目录下生成目录树

    运行  java  包名字.类名字

    8. Java多态中的对象的filed 不具有多态性,如  父类  对象 =  new  子类(), 对象.field  是调用的父类的,即使子类中覆盖了该字段。

    9. instanceof 运算符

    格式: 引用变量名  instanceof  类名(或者接口)  他用于判断前面的对象是否是后面对象的类,子类、实现类的实例,是返回true,否者返回false

    10. Java 中基本数据类型和对应封装类之间的转化

    int   a  =  1;

    Integer  A  =  new Integer(a);

    a  = A.intValue();

    其他的类型也是这样的。

    11.单例(singleton)类 例子

    class Singleton

    {

    private static Singleton instance;

    private Singleton(){}

    public static Singleton getInstance()

    {

    if(instance == null)

    {

    instance = new Singleton();

    }

    return instance;

    }

    public static void main(String[] args)

    {

    Singleton s1 = Singleton.getInstance();

    Singleton s2 = Singleton.getInstance();

    System.out.println(s1 == s2);

    }

    }

    12.final修饰的成员变量初始化问题

    类Field: 必须在静态初始块中或声明该FIeld时指定初始值

    实例Field:必须在非静态初始块中或声明该FIeld时指定初始值或构造器中声明

    13.Final 变量必须显式初始化,系统不会对final变量进行隐式初始化

    14.java会使用常量池来管理曾经用过的字符串直接常量,例如:String a = "java"; ,系统把常量字符串“java”存在常量池,当再次执行 String b = "java";  a == b  是true

    15.final 方法不可以重写,final类不能被继承

    如果用private 方法 和 final private 是一样的

    若果是用final修饰的方法在子类中出现,那是子类新定义的,与父类没有关系

    16.不可变类:创建后该类的Field是不可改变的。java提供了8个基本变量的包装类和string都是不可改变类。

    17.缓存实例的不可改变类

    class CacheImmutale

    {

    private static int MAX_SIZE = 10;

    private static CacheImmutale[] cache = new CacheImmutale[MAX_SIZE];

    private static int pos = 0;

    private final String name;

    private CacheImmutale(String name)

    {

    this. name = name;

    }

    public String getName()

    {

    return name;

    }

    public static CacheImmutale valueOf(String name)

    {

    for(int i = 0; i < MAX_SIZE; ++i)

    {

    if(cache[i] != null && cache[i].getName().equals(name))

    return cache[i];

    }

    if(pos == MAX_SIZE)

    {

    cache[0] = new CacheImmutale(name);

    pos = 1;

    }

    else

    {

    cache[pos++] = new CacheImmutale(name);

    }

    return cache[pos -1];

    }

    public boolean equals(Object obj)

    {

    if(this == obj)

    return true;

    if(obj != null && obj.getClass() == CacheImmutale.class)

    {

    CacheImmutale ci = (CacheImmutale)obj;

    return name.equals(ci.getName());

    }

    return false;

    }

    public int hashCode()

    {

    return name.hashCode();

    }

    }

    public class CacheImmuteTest

    {

    public static void main(String[] args)

    {

    CacheImmutale c1 = CacheImmutale.valueOf("Hello");

    CacheImmutale c2 = CacheImmutale.valueOf("Hello");

    System.out.println(c1 == c2);

    }

    }

    用缓存实例要看某个对象的使用频率,若重复使用那就利大于弊,若不经常使用那弊就大于利

    还有java提供的java.lang.Integer  创建数值在-128-127之间的数采用缓存机制的

    Integer in2 = Integer.valueOf(6);

    Integer in3= Integer.valueOf(6);

    in2 == in3  is true;

    18. static 和 abstract 不能同时修饰一个方法,没有类抽象方法

    19.一个类可以又一个父类,实现多个接口,接口中Filed是public 、static、final的,方法是public abstract的

    20.非静态内部类的方法访问某个变量,搜索顺序为:先内部类中方法内-> 内部类  -> 外部类中如果都找不到则出现编译错误

    import java.util.*;

    public class DiscernVariable

    {

    private String prop = "外部类的实例变量";

    private class InClass

    {

    private String prop = "内部类的实例变量";

    public void info()

    {

    String prop = "局部变量";

    System.out.println("外部类的field值:" + DiscernVariable.this.prop);

    System.out.println("内部类的field值:" + this.prop);

    System.out.println("局部变量的值:" + prop);

    }

    }

    public void test()

    {

    InClass in = new InClass();

    in.info();

    }

    public static void main(String[] args)

    {

    new DiscernVariable().test();

    }

    }

    21.非静态内部类不能有静态方法、静态Field、静态初始化块

    22.在外部类之外访问内部类  访问非静态内部类:outclass.Inclass varname = new outclass().new InClass();

    访问静态内部类:  outclass.Inclass varname = new outclass.Inclass();

    import java.util.*;

    class Out

    {

    class In

    {

    public In()

    {

    System.out.println("非静态内部类构造器");

    }

    }

    }

    public class CreatInnerInstance

    {

    public static void main(String[] args)

    {

    Out.In in = new Out().new In();

    /*

    以上的代码可分开写为:

    Out.In in;

    Out out = new Out();

    in = out.new In();

    */

    }

    }

    class SubClass extends Out.In

    {

    //显示定义SubClass的构造器

    public SubClass(Out out)

    {

    //通过转入的Out对象显示调用In的构造器

    out.super();

    }

    }

    import java.util.*;

    class StaticOut

    {

    static class StaticIn

    {

    public StaticIn()

    {

    System.out.println("静态内部类构造器");

    }

    }

    }

    public class CreatStaticInnerInstance

    {

    public static void main(String[] args)

    {

    StaticOut.StaticIn in = new StaticOut.StaticIn();

    /*

    以上的代码可分开写为:

    StaticOut.StaticIn in;

    in = new StaticOut.StaticIn();

    */

    }

    }

    class SubClass extends StaticOut.StaticIn

    {

    //无须创建内部类实例

    }

    展开全文
  • Java知识点归纳总结

    2020-09-05 10:34:08
    本篇文章对Java的一些知识点进行了归纳总结分析。需要的朋友参考下
  • Java部分基础知识点总结归纳 基本数据类型和流程控制 基本数据类型 基本类型的数据转换遵循此原则: 小转大,直接转;大转小,需强转。 按照数据类型从小到达顺序分为如下: byte<--short<--char<--int&...
  • java知识点归纳

    2017-07-19 09:05:18
    Java知识点总结归纳 流 Java所有的流类位于http://java.io包中,都分别继承字以下四种抽象流类型。 继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是...
  • java修饰符分为两大类,一种是访问修饰符(default、public、private),一种是非访问修饰符(final、abstract、synchronized) 。 默认访问修饰符:同一个包内的类可见,用于修饰:类、接口、变量、方法。 ...
  • 精简,明了,帮助你快速的了解java的基本知识
  • java知识点总结

    2015-11-09 16:14:37
    Java核心知识点 ...博客知识点整理按照上图顺序,进行归纳整理,供后期查询相关知识。 JavaSE最重要的知识点: *面向对象 *Java类集 *JavaIO *JDBC Java软件工程师知识体系 Java学习流程 ...
  • 原标题:Java知识点归纳:Java学习不可不知的5个知识点学习Java知识要循序渐进,多练习,多实践,基础理论的学习不必可少。下面就是千锋广州老师总结出来的5大必学知识点,一起来看一下吧! 1.什么是线程线程是进程...
  • java 知识点总结 应同学要求特意写了一个知识点总结 因比较匆忙可能归纳不是很准确重点是面向对 象的部分 java 有三个版本 JAVA SE 标准版 \JAVA ME 移动版 \JAVA EE企业版 java 常用命令 java, javac, appletview ...
  • 最近又生出了换工作的想法,遂将目前掌握的技术点总结归纳一下,查漏补缺,也为面试准备做个大纲。在这里发布出来,供大家参考,只作为大家成长路上的一片树叶。分类不求甚精细,但求归纳汇总。必有些枝叶不足之处,...
  • 写这篇文章的目的是想总结一下自己这么多年来使用Java的一些心得体会,主要是和一些Java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...
  • 此文章部分引用java3y的《三歪教你Spring》; 简介: Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了...
  • 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...
  • jsp与El,jstl知识点总结归纳 jsp部分 一.jsp的三大指令 page ,include,taglib 1.jsp中的page指令 —设置jsp 例如: ”java” contentType=”text/html; charset=UTF-8” pageEncoding=
  • java知识点总结ing

    2019-10-02 07:47:24
     对象:是具体的事物 xiaoming xiaohong 类:是对对象的抽象(抽象 抽出象的部分)Person 先有具体的对象,然后抽象各个对象之间象的部分,归纳出类通过类再认识其他对象。 【生活案例】  类是一个图纸 对象...
  • java中I/O的操作主要是靠java.io包下面的类和接口来实现的,进入输入,输出操作.输入也可以叫做读取数据,输出也可以叫做写入数据. IO分类 根据数据的流向分为:输入流和输出流 输入流:把数据从其他设备上读取到内存...
  • 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...
  • 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...
  • 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...
  • Java基础知识点总结

    2018-11-14 12:56:05
    本文档是作者在听完刘意老师所讲的Java基础课程后,对老师所讲内容的一个归纳总结
  • 以下简单介绍了下我对于这些java基本知识点和技术点的一些看法和心得,这些内容都源自于我这些年来使用java的一些总结
  • java解惑——易错知识点归纳总结

    千次阅读 2016-08-21 07:46:19
    一. Switch 1.其能接受的数据类型有四个,char , byte, short, int 2.Default 可放在switch中的任何一个地方,但只有给定的条件匹配不到时,才会执行 3.Case,default语句如果执行完要跳出...[java] view plain cop
  • 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...
  • 写这篇文章的目的是想总结一下自己这么多年来使用Java的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行当的准新手们,希望可以给大家一些经验,能...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 372
精华内容 148
关键字:

java知识点总结归纳

java 订阅