首页 > 技术文章 > java知识点1

lanqie 2018-04-03 11:02 原文

本系列文章源自大神--纯洁的微笑的博客 http://www.cnblogs.com/ityouknow/

基础篇

JVM

JVM内存结构

  • 堆、栈、方法区、直接内存、堆和栈区别

内存结构图

控制参数


-Xms设置堆的最小空间大小。
-Xmx设置堆的最大空间大小。
-XX:NewSize设置新生代最小空间大小。
-XX:MaxNewSize设置新生代最大空间大小。
-XX:PermSize设置永久代最小空间大小。
-XX:MaxPermSize设置永久代最大空间大小。
-Xss设置每个线程的堆栈大小。
-XX:NewRatio设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

堆和栈区别

Java内存模型

  • 内存可见性、重排序、顺序一致性、volatile、锁、final

垃圾回收

  • 内存分配策略、垃圾收集器(G1)、GC算法、GC参数、对象存活的判定

http://www.cnblogs.com/ityouknow/p/5614961.html
http://www.cnblogs.com/ityouknow/p/7550068.html
http://www.cnblogs.com/lirenzuo/tag/JVM/

JVM参数及调优

Java对象模型

  • oop-klass、对象头

HotSpot

  • 即时编译器、编译优化

类加载机制

  • classLoader、类加载过程、双亲委派(破坏双亲委派)、模块化(jboss modules、osgi、jigsaw)

加载的过程包括了加载、验证、准备、解析、初始化五个阶段

加载的例子:

public class Hello {

    static {
        System.out.println("静态代码块");
    }

    public Hello() {
        System.out.println("构造方法");
    }
}
public class AppTest {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader classLoader = AppTest.class.getClassLoader();
        System.out.println(classLoader);
        System.out.println(classLoader.getParent());
        //1.初始化时不执行静态块
        classLoader.loadClass("com.xh.dubbo.demon.Hello");
        //2.初始化时不执行静态块
        Class.forName("com.xh.dubbo.demon.Hello", false, classLoader);
        //3.初始化时执行静态块
        Class.forName("com.xh.dubbo.demon.Hello");
    }
}

结果:

sun.misc.Launcher$AppClassLoader@1d44bcfa
sun.misc.Launcher$ExtClassLoader@2b193f2d
静态代码块

初始化:

初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:

①声明类变量是指定初始值
②使用静态代码块为类变量指定初始值

JVM初始化步骤

1、假如这个类还没有被加载和连接,则程序先加载并连接该类
2、假如该类的直接父类还没有被初始化,则先初始化其直接父类
3、假如类中有初始化语句,则系统依次执行这些初始化语句

类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:

– 创建类的实例,也就是new的方式
– 访问某个类或接口的静态变量,或者对该静态变量赋值
– 调用类的静态方法
– 反射(如Class.forName(“com.shengsiyuan.Test”))
– 初始化某个类的子类,则其父类也会被初始化
– Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类
例子:

public class A {

    static {
        System.out.println("A静态代码块");
    }

    public A() {
        System.out.println("A构造方法");
    }
}
public class B extends A{

    static {
        System.out.println("B静态代码块");
    }

    public B() {
        System.out.println("B构造方法");
    }
}
new B();

结果:

A静态代码块
B静态代码块
A构造方法
B构造方法

虚拟机性能监控与故障处理工具

  • jps, jstack, jmap、jstat, jconsole, jinfo, jhat, javap, btrace、TProfiler

参考:https://blog.csdn.net/yuxin6866/article/details/77718748

S0C:年轻代中第一个survivor(幸存区)的容量 (kb)
S1C:年轻代中第二个survivor(幸存区)的容量 (kb)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (kb)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (kb)
EC:年轻代中Eden(伊甸园)的容量 (kb)
EU:年轻代中Eden(伊甸园)目前已使用空间 (kb)
OC:Old代的容量 (kb)
OU:Old代目前已使用空间 (kb)
PC:Perm(持久代)的容量 (kb)
PU:Perm(持久代)目前已使用空间 (kb)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
NGCMN:年轻代(young)中初始化(最小)的大小 (kb)
NGCMX:年轻代(young)的最大容量 (kb)
NGC:年轻代(young)中当前的容量 (kb)
OGCMN:old代中初始化(最小)的大小 (kb)
OGCMX:old代的最大容量 (kb)
OGC:old代当前新生成的容量 (kb)
PGCMN:perm代中初始化(最小)的大小 (kb)
PGCMX:perm代的最大容量 (kb)
PGC:perm代当前新生成的容量 (kb)
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (kb)
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (kb)
ECMX:年轻代中Eden(伊甸园)的最大容量 (kb)
DSS:当前需要survivor(幸存区)的容量 (kb)(Eden区已满)
TT: 持有次数限制
MTT : 最大持有次数限制
  • jstat -gcutil pid
  • jstat -gc pid
  • jstat -gccapacity pid
  • jstat -gcnew pid
  • jstat -gcnewcapacity pid
  • jstat -gcold pid
  • jstat -gcoldcapacity pid
  • jstat -gcpermcapacity pid
  • jstat -class pid
  • jstat -compiler pid
  • jstat -printcompilation pid

gc日志分析

  • 启用日志
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-Xloggc:./mygc.log

/mygc.log这个路径在项目下,当然也可以写绝对路径

  • 分析日志

利用在线分析工具http://gceasy.io
上传打包好的日志文件

编译与反编译

  • javac 、javap 、jad

java源码(AppTest.java)

package com.xh.dubbo.demon;

/**
 * Unit test for simple App.
 */
public class AppTest {

    public static void main(String[] args) {
        System.out.println("hello");
    }
}

javac 编译

javac -d . AppTest.java 

得到com/xh/dubbo/demon/AppTest.class,-d主要是指定目录

运行

java com.xh.dubbo.demon.AppTest

反编译查看字节码

javap -c com/xh/dubbo/demon/AppTest.class 
Compiled from "AppTest.java"
public class com.xh.dubbo.demon.AppTest {
  public com.xh.dubbo.demon.AppTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String hello
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

反编译查看源码

jad com/xh/dubbo/demon/AppTest.class

生成AppTest.jad 文件,内容如下:

// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   AppTest.java

package com.xh.dubbo.demon;

import java.io.PrintStream;

public class AppTest
{

    public AppTest()
    {
    }

    public static void main(String args[])
    {
        System.out.println("hello");
    }
}

Java基础知识

阅读源代码

  • String、Integer、Long、Enum、BigDecimal、ThreadLocal、ClassLoader & URLClassLoader、ArrayList & LinkedList、 HashMap & TreeMap&LinkedHashMap &CouncurrentHashMap、HashSet & LinkedHashSet & TreeSet

Java中各种变量类型

熟悉Java String的使用,熟悉String的各种函数

  • JDK 6和JDK 7中substring的原理及区别、
  • replaceFirst、replaceAll、replace区别、
  • String对“+”的重载、
  • String.valueOf和Integer.toString的区别、
  • 字符串的不可变性

自动拆装箱

  • Integer的缓存机制

熟悉Java中各种关键字

  • transient、instanceof、volatile、synchronized、final、static、const 原理及用法。

final:

· 对基本数据类型来说,对于类变量(static)和全局变量,如果不显式地对其赋值而直接使用,则系统会为其赋予默认的零值,而对于局部变量来说,在使用前必须显式地为其赋值,否则编译时不通过。
· 对于同时被static和final修饰的常量,必须在声明的时候就为其显式地赋值,否则编译时不通过;而只被final修饰的常量则既可以在声明时显式地为其赋值,也可以在类初始化时显式地为其赋值,总之,在使用前必须为其显式地赋值,系统不会为其赋予默认零值。

        public static final String a = "a";
        public final String b;
        public final String c = "c";
    
        public static final String[] a_array = null;
        public final String[] b_array;
    
        public AppTest(String b) {
            this.b = b;
            b_array = new String[0];
        }

集合类

  • 常用集合类的使用
  • ArrayList和LinkedList和Vector的区别
  • SynchronizedList和Vector的区别
  • HashMap、HashTable、ConcurrentHashMap区别
  • Java 8中stream相关用法
  • apache集合处理工具类的使用
  • 不同版本的JDK中HashMap的实现的区别以及原因

枚举

  • 枚举的用法、枚举与单例、Enum类
    public enum Color {  
      RED, GREEN, BLANK, YELLOW  
    }  

public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    // 普通方法  
    public static String getName(int index) {  
        for (Color c : Color.values()) {  
            if (c.getIndex() == index) {  
                return c.name;  
            }  
        }  
        return null;  
    }  
}

Java IO&Java NIO,并学会使用

  • bio、nio和aio的区别、三种IO的用法与原理、netty

Java反射与javassist

  • 反射与工厂模式、 java.lang.reflect..

Java序列化

  • 什么是序列化与反序列化、为什么序列化
  • 序列化底层原理
  • 序列化与单例模式
  • protobuf
  • 为什么说序列化并不安全

注解

  • 元注解、自定义注解、Java中常用注解使用、注解与反射的结合

参考:http://www.importnew.com/17413.html,http://www.importnew.com/10294.html

J2SE5.0版本在 java.lang.annotation提供了四种元注解,专门注解其他的注解:
@Documented –注解是否将包含在JavaDoc中
@Retention –什么时候使用该注解
@Target? –注解用于什么地方
@Inherited – 是否允许子类继承该注解
@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。
@Retention– 定义该注解的生命周期。
RetentionPolicy.SOURCE – 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
RetentionPolicy.CLASS – 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
RetentionPolicy.RUNTIME– 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
@Target – 表示该注解用于什么地方。如果不明确指出,该注解可以放在任何地方。以下是一些可用的参数。需要说明的是:属性的注解是兼容的,如果你想给7个属性都添加注解,仅仅排除一个属性,那么你需要在定义target包含所有的属性。
ElementType.TYPE:用于描述类、接口或enum声明
ElementType.FIELD:用于描述实例变量
ElementType.METHOD
ElementType.PARAMETER
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.ANNOTATION_TYPE 另一个注释
ElementType.PACKAGE 用于记录java文件的package信息
@Inherited – 定义该注释和子类的关系

package com.journaldev.annotations;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
    public @interface MethodInfo{
    String author() default 'Pankaj';
    String date();
    int revision() default 1;
    String comments();
}

package com.journaldev.annotations;
 
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
 
public class AnnotationExample {
 
public static void main(String[] args) {
}
 
@Override
@MethodInfo(author = 'Pankaj', comments = 'Main method', date = 'Nov 17 2012', revision = 1)
public String toString() {
    return 'Overriden toString method';
}
 
@Deprecated
@MethodInfo(comments = 'deprecated method', date = 'Nov 17 2012')
public static void oldMethod() {
    System.out.println('old method, don't use it.');
}
 
@SuppressWarnings({ 'unchecked', 'deprecation' })
@MethodInfo(author = 'Pankaj', comments = 'Main method', date = 'Nov 17 2012', revision = 10)
public static void genericsTest() throws FileNotFoundException {
    List l = new ArrayList();
    l.add('abc');
    oldMethod();
}
 
}

package com.journaldev.annotations;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
 
public class AnnotationParsing {
 
public static void main(String[] args) {
    try {
    for (Method method : AnnotationParsing.class
        .getClassLoader()
        .loadClass(('com.journaldev.annotations.AnnotationExample'))
        .getMethods()) {
        // checks if MethodInfo annotation is present for the method
        if (method.isAnnotationPresent(com.journaldev.annotations.MethodInfo.class)) {
            try {
        // iterates all the annotations available in the method
                for (Annotation anno : method.getDeclaredAnnotations()) {
                    System.out.println('Annotation in Method ''+ method + '' : ' + anno);
                    }
                MethodInfo methodAnno = method.getAnnotation(MethodInfo.class);
                if (methodAnno.revision() == 1) {
                    System.out.println('Method with revision no 1 = '+ method);
                    }
 
            } catch (Throwable ex) {
                    ex.printStackTrace();
                    }
        }
    }
    } catch (SecurityException | ClassNotFoundException e) {
            e.printStackTrace();
         }
    }
 
}

结果:

Annotation in Method 'public java.lang.String com.journaldev.annotations.AnnotationExample.toString()' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=1, comments=Main method, date=Nov 17 2012)
Method with revision no 1 = public java.lang.String com.journaldev.annotations.AnnotationExample.toString()
Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.oldMethod()' : @java.lang.Deprecated()
Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.oldMethod()' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=1, comments=deprecated method, date=Nov 17 2012)
Method with revision no 1 = public static void com.journaldev.annotations.AnnotationExample.oldMethod()
Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.genericsTest() throws java.io.FileNotFoundException' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=10, comments=Main method, date=Nov 17 2012)

JMS

  • 什么是Java消息服务、JMS消息传送模型

JMX

  • java.lang.management..、 javax.management..

泛型

  • 泛型与继承
package com.xh.dubbo.demon;

/**
 * Unit test for simple App.
 */
public class AppTest<T> {

    //静态泛型方法
    public static <T> T hello(T t) {
        return t;
    }

    public static void main(String[] args) {
        Generic<String> generic_str = new Generic<String>("hello ");
        Generic<Integer> generic_int = new Generic<Integer>(123);
        Generic<Number> generic_num = new Generic<Number>(333);


        test4Generic(generic_num);
        test4Generic(generic_int);
        test4Generic(generic_str);//编译期报错:(com.xh.dubbo.demon.Generic<? extends java.lang.Number>)in AppTest cannot be applied to (com.xh.dubbo.demon.Generic<java.lang.String>)


    }

    private static void test4Generic(Generic<? extends Number> generic) {
    }

}

//泛型类
class Generic<T> {
    private T t;

    public Generic(T t) {
        this.t = t;
    }

    public T get() {
        return this.t;
    }

    //泛型方法
    public <T> T genericMethod1(T t1) {
        return (T) this.get();
    }

    //泛型方法
    public <E> E genericMethod2(E e1) {
        return (E) this.get();
    }
}

//泛型接口
interface IGeneric<T> {
    void add(T t);
}

  • 类型擦除

  • T和? 对比


    /**
     * ? 在参数中约束
     *
     * @param animals1
     * @param animals2
     */
    static void test_1(List<? extends Animal> animals1, List<? super Dog> animals2) {

    }

    /**
     * ? 不能在返回值前面约束
     */
    static <?extends Animal> void test_2() {

    }

    /**
     * T 不能在参数中约束
     *
     * @param animals1
     * @param animals2
     */
    static void test1(List<T extends Animal> animals1, List<T super Animal> animals2) {

    }

    /**
     * T 可以在返回值前面约束
     *
     * @param t
     * @param <T>
     */
    static <T extends Animal & Serializable> void test2(T t) {

    }

Java泛型只存在于源码中,在编译后的字节码文件中,就已经被替换为原来的原生类型了,并且在相应的地方插入了强制转型代码。对于运行期的java语言来说,ArrayList<int>和ArrayList<String>就是同一个类.

单元测试

  • junit、mock、mockito、内存数据库(h2)

正则表达式

  • java.lang.util.regex..

常用的Java工具库

  • commons.lang, commons... guava-libraries netty

什么是API&SPI

原文:https://blog.csdn.net/e5945/article/details/24050127

     先描述下API(Application Programming Interface )。在java中,我们使用java提供的很多类、类的方法、数据结构来编写我们的应用程序,最终完成我们需求的程序功能,这里的类、方法、数据结构即是jdk提供的api。api的意义,其实就是这些提供给你完成某项功能的类、接口或者方法。
     而SPI(Service Provider Interface)是指一些提供给你继承、扩展,完成自定义功能的类、接口或者方法。
     API直接为你提供了功能,你使用API就能完成任务。
     SPI是一种回调的思想,回调是指我们在使用api时,我们可以向api传入一个类或者方法,api在合适的时间调用类或者方法。SPI是在一些通用的标准中,为标准的实现产商提供的扩展点。标准在上层提供API,API内部使用了SPI,当API被客户使用时,会动态得从当前运行的classpath中寻找该SPI的实现,然后使用该SPI的实现来完成API的功能。
     SPI的实现方式是:提供实现的实现类打包成Jar文件,这个Jar文件里面必须有META-INF目录,其下又有services目录,其下有一个文本文件,文件名即为SPI接口的全名,文件的内容该jar包中提供的SPI接口的实现类名。
     举一个著名的例子:
     mysql的驱动包提供了java.sql.Driver这个SPI的实现,实现类是com.mysql.jdbc.Driver,在mysql-connector-java-5.1.6.jar中,我们可以看到有一个META-INF/services目录,目录下有一个文件名为java.sql.Driver的文件,其中的内容是com.mysql.jdbc.Driver。 
     在运行DriverManager.getDriver并传入参数“com.mysql.jdbc.Driver”时,DriverManager会从mysql-connector-java-5.1.6.jar中找到com.mysql.jdbc.Driver并实例化返回一个com.mysql.jdbc.Driver的实例。

异常

  • 异常类型、正确处理异常、自定义异常

时间处理

  • 时区、时令、Java中时间API

编码方式

  • 解决乱码问题、常用编码方式

Java并发编程

什么是线程,与进程的区别

阅读源代码,并学会使用

  • Thread、Runnable、Callable、ReentrantLock、ReentrantReadWriteLock、Atomic、Semaphore、CountDownLatch、、ConcurrentHashMap、Executors

线程池

线程安全

  • 死锁、死锁如何排查、Java线程调度、线程安全和内存模型的关系

  • CAS、乐观锁与悲观锁、数据库相关锁机制、分布式锁、偏向锁、轻量级锁、重量级锁、monitor、锁优化、锁消除、锁粗化、自旋锁、可重入锁、阻塞锁、死锁

死锁

volatile

  • happens-before、编译器指令重排和CPU指令重

synchronized

  • synchronized是如何实现的?
  • synchronized和lock之间关系
  • 不使用synchronized如何实现一个线程安全的单例

sleep 和 wait

wait 和 notify

notify 和 notifyAll

ThreadLocal

写一个死锁的程序

写代码来解决生产者消费者问题

守护线程

  • 守护线程和非守护线程的区别以及用法

推荐阅读