本篇文章更多是用来总结,具体详细可参看文章中帖子链接。
1.九种基本数据类型的大小,以及他们的封装类。
- boolean, byte, char, short, int, long, float, double, void.
- Boolean, Byte, Character, Short, Integer, Long, Float, Double, Void.
2.Switch能否用string做参数?
- jdk1.7之前,可以。诸如long,float,double等都会强制转换为int,string不可以。
- jdk1.7之后,string通过调用switch中的string.hasCode,将string转为int。
3.equals与==的区别。
- JVM内存分配问题
- 在JVM中 内存分为栈内存和堆内存。
当我们创建一个对象(new Object)时,就会调用它的构造函数来开辟空间,将对象数据存储到堆内存中,与此同时在栈内存中生成对应的引用,当我们在后续代码中调用的时候用的都是栈内存中的引用,还需注意的一点,基本数据类型是存储在栈内存中。、 - == 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。
- equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象。
- 在JVM中 内存分为栈内存和堆内存。
4.Object有哪些公用方法?
- clone、equals、hashCode、getClass、wait、notify、notifyAll、toString等。
- 具体详解看Object有哪些公用的方法?
5.Java的四种引用,强软弱徐,用到的场景。(Java 如何有效地避免OOM:善于利用软引用和弱引用)
- 从jdk1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期,这四种级别由高到低分别是强、软、若、虚引用。
- 强引用, 强引用是最普遍的引用,如果一个对象具有强引用,那么当内存空间不足时,JVM即使抛出OOM,也不会回收它。
- 软引用 是用来描述有用但不是必须的对象,在Java中用java.lang.ref.SoftReference类来表示,该对象只有在内存不足的时候JVM才会回收该对象,因此这一点可以很好地解决OOM问题,并且这个特性很适合用来实现缓存,如网页、图片缓存等。
SoftReference
sr = new SoftReference (new String("hello")); - 弱引用 弱引用也是用来描述非必需对象,弱与软区别在于:当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。不过由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。具体使用方式将上面代码SoftReference改成WeakReference即可,不过需要注意的是这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象。(软引用也如此)
- 虚引用 PhantomReference 顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动,和前面引用的区别在于,虚引用必须和引用队列联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中,如果程序发现某个虚引用已经被加入引用队列中,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
6.Hashcode的作用(java中的==、equals和hashCode以及hashCode生成)
- hashCode()返回的是一个数值,我们可以称之为hashCode,从方法的名称上可以看出,其目的是生成一个hash码。对于集合类如HashSet、HashMap等,存入流程为:
- 根据对象的hash码,经过hash算法,找到对象应该存放的位置。
- 如果位置为空,则将对象存入该位置;
- 如果位置不为空,则使用equals()比较该位置的对象和将要存入的对象。
- 如果两个对象相等,则不再插入;
- 如果不相等,则根据hash冲突解决算法将对象插入其他位置。
- 因此上面的需要满足两点:
- 对于equals()相等的两个对象,其hashCode()返回的值一定相等。
- 对于equals()不同的对象要尽量做到hash码不同。
7.ArrayList、LinkedList、Vector的区别(比较ArrayList、LinkedList、Vector)。
- ArrayList是最常用的List实现类,内部通过数组实现,允许对某个元素进行快速随机访问。
- Vector和ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
- LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。
8. String、StringBuffer与StringBuilder的区别(String、StringBuffer与StringBuilder之间区别)。
- 三者在执行速度方面的比较:StringBuilder > StringBuffer > String
- StringBuilder:线程非安全的;StringBuffer:线程安全的
9. Map、Set、List、Queue、Stack的特点与用法(Map、Set、List、Queue、Stack的特点与用法)。
- Map保存的是"键值对",就像一个小型数据库。我们可以通过"键"找到该键对应的"值"
- Set不能有重复元素
- List必须保持元素特定的顺序
- Queue保持一个队列(先进先出)的顺序
- Stack是Vector提供的一个子类,用于模拟"栈"这种数据结构(LIFO后进先出
10.HashMap和HashTable的区别(HashMap和Hashtable的区别)。
- Hashtable是个过时的集合类,在Java 4中被重写了,实现了Map接口,所以自此以后也成了Java集合框架中的一部分。
- 主要的区别有:线程安全性,同步,以及速度。
- HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(包括key和value)
- 承接上一条,由于HahsMap是非同步的,HashTable是同步的,因此Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。
- 也因为HashTable是同步的,因此单线程情况下速度要比HashMap慢。
11、12、13没有写
14.try catch finally,try里有return,finally还执行么?
- 不管有木有出现异常、或者当try和catch中有return时,finally都会执行。
- 函数返回值是在finally执行前确定的。
- finally是在return后面的表达式运算后执行,而此时并没有返回运算后的值,而是先把要返回的值保存起来,所以finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
15.Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况([Java] Excption与Error包结构,OOM和SOF)
- Excption与Error包结构
- Thowable类是java语言中所有错误或异常的超类,只有当对象是此类或其子类之一的实例时,才能通过JVM抛出,才是catch子句中的参数类型。Java可将Thowable的结构分为三种类型。
- Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等,Java虚拟机抛出一个Error对象,JVM一般会选择线程终止。
- Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
- SOF你遇到过哪些情况(堆栈溢出 StackOverflow)。
- 递归是利用堆栈来实现的,而 内存分配中栈区的大小在编译的时候确定,可能为1M或2M,所以溢出原因包括:递归调用、大量循环或死循环、全局变量是否过多、数组、List、Map数据过大。
- Android的OOM
- 当内存占有量超过了虚拟机分配的最大值时就会产生内存溢出(JVM里分配不出更多的page),
- 一般在以下情况出现
- 加载的图片太多或图片过大
- 分配特大的数组
- 内存里资源过多切来不及释放
- 解决方法
- 在内存引用上做处理,合理使用软引用
- 对图片做边界压缩,配合软引用使用
- 显示调用GC进行内存回收
16. Java面向对象的三个特征与含义Java面向对象的三大特征
- 封装。将某事物的属性和行为包装到对象中。
- 继承。对父类方法或对接口的继承,易于扩展,降低耦合。
- 多态。java中的固定方法,体现在overriding(复写)上,复写是面向中的多态。多态是指父对象中的同一个行为能在其多个子对象中有不同的表现。
17.Override和Overload的含义及区别。
- 重写(方法覆盖):在Java中,子类可以继承父类中的方法,而不需要重新编写相同的方法,但有时候子类并不想原封不动的继承父类的方法,而是想作一定的修改,这就需要采用方法的重写,故重写又称方法覆盖,特性如下:
- 必须是在继承(extends)里。
- 方法名、参数个数和参数类型必须都相同。
- jdk1.5以后,返回值类型可以与父类相同,也可以与父类不同,但要求返回值是父类的子类,比如父类的返回值是Object,那么子类的返回值可以是其子类String。
- 派生类重写方法的访问权限不能低于基类的权限。
- 重载:在同一作用域内,函数(或方法)有相同的名称,但是参数列表不相同的情况,这样的函数或者方法之间,互相称之为重载函数(或方法)。这样做的好处是减少了函数名的数量,避免了名字空间的污染,提高程序可读性。
- 函数名相同。
- 参数列表不同(包括参数个数和参数类型)。
- 返回类型可相同可不同。
18.Interface与abstract类的区别接口和抽象类有什么区别。
- abstract class和interface是支持抽象类定义的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。
- abstract:子类只能继承一个父类,子类和父类是is a的关系
- 因为父类是抽象方法,因此子类必须重写所有父类的抽象方法(但父类若不是abstract,而是普通方法,则可以重写,也可以不重写)。
- interface:子类可以实现多个接口,子类和父类是like a的关系
- 一个类实现某个接口,是否要重写接口中的所有方法,关键要看子类是否是抽象类,如果是普通类,则必须实现接口中的所有方法,如果是抽象类,则可以不实现所有方法。
- 相同点:
- 两者都是抽象类,都不能实例化。
- interface及abstact的子类都必须要实现已经声明的抽象方法。
- 不同点:
- 一个类只能继承一个抽象类,但可以实现多个接口。
- interface每一个方法都是抽象方法,实现类必须要实现,而抽象类的子类可以有选择的实现。其中有选择包括两个含义:
- 抽象类中冠有abstact的方法才是抽象的,子类必须实现,没有abstact的,抽象类中必须定义方法体。
- 抽象类的子类在继承它时,对其中的非抽象类方法既可以直接继承不实现,也可以覆盖;对于抽象方法,可以选择实现,也可以子类本身为抽象方法,只继承不实现,但需要通过再次声明其方法为抽象方法。
18.1(临时想到的)static和final的区别Java关键字final、static使用总结
- final:表示“无法改变”、“终态”的意思,你可能出于两种理解而需要阻止改变:设计或效率。
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类方法重写,但可以被继承。使用final方法的两个原因:
- 把方法锁定,防止任何继承类修改它的意义和实现。
- 高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造函数。
- static:表示“全局”或“静态”的意思,被static修饰的成员变量和成员方法独立于该类的任何对象,也就是说它不依赖类特定的实例,被类的所有实例共享。
- static final:代表“全局常量”
- 对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
- 对于方法,表示不可覆盖,并且可以通过类名直接访问。
- 对于被static和final修饰过的实例常量,实例本身不能再改变了,但对于一些容器类型(比如,ArrayList、HashMap)的实例变量,不可以改变容器变量本身,但可以修改容器中存放的对象,这一点在编程中用到很多。
19没有写
20.java多态的实现原理Java技术——多态的实现原理。
- 方法重写后的动态绑定:多态允许具体访问时,实现方法的动态绑定。Java对于动态绑定的实现主要依赖于方法表,通过继承和接口的多态有所不同。
- 这里动态调用分为两种,类引用调用和接口引用调用
- 类引用调用过程(父类中的任意一个方法,在它们的方法表和其子类的方法表中的位置是一样的)
- 在常量池中找到方法调用的符号引用
- 查看父类的方法表,得到某方法在父类方法表中的偏移量(假设为15),这样就得到该方法的直接引用。
- 根据this指针得到具体对象(即子类所指向的位于堆中的对象)
- 根据对象得到该对象的方法表,根据偏移量15查看有无重写该方法,如果重写,则直接调用子类方法代码,若无重写,查找父类有无该方法。
- 接口引用调用过程(由于可实现多接口,这样同样的方法在基类和派生类中方法表的位置就可能不一样了)
- java对于接口方法的调用采用搜索子类中整个方法表的方式。
- 所以因为每次都要搜索,接口方法的调用慢于类方法的调用。
21.实现多线程的两种方法:Thread类与Runable接口Java中 Thread和Runnable实现多线程的区别和联系
- 联系
- Thread类实现了Runable接口。
- 都需要重写里面Run方法。
- 区别
- 实现Runnable接口的类更具有健壮性,避免了单继承的局限。
- Runnable更容易实现资源共享,能多个线程同时处理一个资源。
22.线程同步的方法:sychronized关键字、lock接口、可重入锁reentrantLock等。
- 线程同步的方法:sychronized、lock、reentrantLock等总结分析
- java线程同步:synchronized关键字,Lock接口以及可重入锁ReentrantLock
- Lock应用之 可中断
- 如果你向一个变量写值,而这个变量接下来可能会被另一个线程所读取,或者你从一个变量读值,而它的值可能是前面由另一个线程写入的,此时你就必须使用同步
- 写法:
public void run() {
int loopTimes = 10000;
while (loopTimes > 0) {
//sychronized关键字:
synchronized (this) {
counter ++;
}
loopTimes --;
}
}
private final Lock lock = new ReentrantLock();
public void run() {
int loopTimes = 10000;
while (loopTimes > 0) {
try {
//ReentrantLock写法
lock.lock();
counter ++;
} finally {
lock.unlock();
}
loopTimes --;
}
}
- 两者的最佳实践
- 在资源竞争不激烈,偶尔有同步时,用sychronized关键字,因为编译程序会尽可能优化sychronized关键字,另外可读性非常好。
- ReentrantLock提供了多样化的同步,比如有时间的同步,可以被打断的同步(sychronized是不能被Interrupt的),在竞争不激烈时,ReentrantLock比sychronized差一点,在竞争激烈时,synchronized能性能下降好几十倍,而ReentrantLock维持常态。
23没有写
24.写出生产者消费者模式。
- 生产者/消费者问题的多种Java实现方式
- Java并行编程-lock中使用多条件condition(生产者消费者模式实例)
- 很多后台服务程序并发控制的基本原理都可以归纳为生产者/消费者模式,属于操作系统课程。
- 生产者消费者问题是研究多线程程序时绕不开的经典问题之一。
- 它描述的是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。
- 采用某种机制保护生产者和消费者之间的同步,可以解决生产者/消费者问题。
- 同步问题的核心在于:如何保证同一资源被多个线程并发访问时的完整性。
- 常用的同步方法是采用信号或加锁机制,保证资源在任何时刻至多被一个线程访问。
- Java的三个同步方法
- wait() / notify()方法
- await() / signal()方法
- 用到了condition,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 通信方法的使用。
- 在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。
- Condition的强大之处在于它可以为多个线程间建立不同的Condition, 使用synchronized/wait()只有一个阻塞队列,notifyAll会唤起所有阻塞队列下的线程,而使用lock/condition,可以实现多个阻塞队列,signalAll只会唤起某个阻塞队列下的阻塞线程。
- BlockingQueue阻塞队列方法(写法最简单了)
25.ThreadLocal的设计理念与作用。
- ThreadLocal的设计理念与作用
- Java中ThreadLocal类的作用以及实现原理
- 作用
为每一个使用该变量的线程提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其他的线程副本冲突,从线程的角度看,就好像每一个线程都完全拥有该变量。 - 设计理念
在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
26.ThreadPool用法与优势。
Java笔试面试题整理第六波(修正版)
- 优势
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。
- 用法流程
- 首先线程池判断基本线程池是否已满(< corePoolSize ?)?没满,创建一个工作线程来执行任务。满了,则进入下个流程。
- 其次线程池判断工作等待队列是否已满?没满,则将新提交的任务存储在工作等待队列里。满了,则进入下个流程。
- 最后线程池判断整个线程池是否已满(< maximumPoolSize ?)?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。
public static ExecutorService newFixedThreadPool(int nThreads) {
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
}
//该方法没有返回值,也就不能判断任务是否被线程池执行成功
threadpool.execute(new Runnable(){...});
//或者
Future> future = threadpool.submit(new Runnable(){...});
try {
//get方法会阻塞住直到任务完成
Object res = future.get();
} catch (InterruptedException e) {
// 处理中断异常
e.printStackTrace();
} catch (ExecutionException e) {
// 处理无法执行任务异常
e.printStackTrace();
}finally{
// 关闭线程池
executor.shutdown();
}
27没写
28. wait()和sleep()的区别。
wait()和sleep()的区别
- sleep()控制范围由当前线程决定。wait()由某个确定的对象来调用。
- 两者都可以让线程暂停一段时间,但sleep()是一个线程的运行状态控制,wait()是线程之间的通信问题。
- 这两个方法来自不同的类,分别是sleep()来自Thread和wait()
来自Object - sleep()可以将一个线程睡眠,参数可以指定一个时间;而wait()可以将一个线程挂起,直到超时或者该线程被唤醒。
- 最主要是sleep方法没有释放锁,依然保持着锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
- wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
29. foreach与正常for循环效率对比。
- Java迭代器(转)(iterator详解以及和for循环的区别)
- Java for循环和foreach循环的性能比较
- 如果循环数组结构的数据时,for更快,因为for采用下标访问。
- 循环链表结构的数据时,foreach更快,因为iterator中的next()方法,采用的即是顺序访问的方法。
- foreach和for最大的不同在于remove(), 因为forEach不是关键字,关键字还是for,语句是由iterator实现的。迭代器iterator的remove()方法,不仅会删除元素,还会维护一个标志。
- 使用 Iterator 的好处在于可以使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现(只要它实现了 java.lang.Iterable 接口)
30. Java IO与NIO(New IO)
- Java NIO系列教程(十二) Java NIO与IO(整体总结清晰明了)
- Java NIO与IO的区别和比较(前面的实际例子举的好)
- Java NIO 与 IO之间的区别(前面总结得好)
- 使用场景
- 果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,使用NIO
- 如果需要管理同时打开不太多的连接,每个会发送大量的数据,使用IO。
- 区别
- IO是面向流的,NIO是面向缓冲区的
- IO每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方;
- NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
- IO流是阻塞的,NIO流是不阻塞的
- 当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了
- 一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
- 选择器
- NIO的选择器允许一个单独的线程来监视和管理多个输入通道
- IO是面向流的,NIO是面向缓冲区的
31. 反射的作用与原理。
- 框架使用java反射好处
- Java的反射原理简析
- 原理(解释)
- 指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制.
- 优点
- 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
- 与Java动态编译相结合,可以实现无比强大的功能。
- 缺点
- 使用反射的性能较低
- 破坏了类的封装性,可以通过反射获取这个类的私有方法和属性 ,使得相对来说不安全。
- 原理:
- 在JVM中寻找可用的Class对象缓存
- 若没有找到,则在JVM中创建并返回cache
- 每次getMethod获取到的方法对象都持有对根对象的引用
- 所有代表同一个方法的方法对象都共享着根对象的MethodAccessor,每一次创建都会调用根对象的复制方法复制一份
32. 泛型常用特点
Java:泛型类型使用总结
- 泛型好处
- 类型安全,使用泛型可以使编译器知道变量的类型限制。
- 消除强制类型转换。泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。
- 性能收益,由于泛型会给 Java 编译器和虚拟机带来更多的类型信息,因此利用这些信息对 Java 程序做进一步优化将成为可能。
33——35没有写
36. 设计模式:单例、工厂、适配器、责任链、观察者等等(没有写责任链)
- 单例
- 单例对象能保证在一个JVM中,该对象只有一个实例存在。好处如下
- 对于大型对象,创建比较频繁,单例能节省开销。
- 省去new操作符,降低系统内存使用率,减轻GC压力。
- 有些类如交易所的核心交易引擎,创建多个会引起混乱。
- 单例对象能保证在一个JVM中,该对象只有一个实例存在。好处如下
- 工厂模式(分为三类)
Java设计模式——工厂模式
- 简单工厂模式
- 工厂类角色,本模式核心,用来创建产品。
- 抽象产品角色,一般是具体产品的父类或接口。
- 具体产品角色,由一个具体类实现。
- 工厂方法模式(分担了对象承受压力,并且使对象变得灵活)
- 抽象工厂角色,工厂方法核心,具体工厂角色的父类或接口。
- 抽象产品角色
- 具体工厂角色
- 具体产品角色
- 抽象工厂模式(在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。抽象工厂模式包含工厂方法模式。)
- 抽象工厂角色
- 抽象产品角色
- 具体工厂角色
- 具体产品角色
- 适配器模式
适配器模式(Adapter):类适配器、对象适配器
- 作用:把一个类的接口转变成客户端所期待的另一种接口,从而使原本因借口不匹配而无法在一起工作的两个类能够在一起工作。
- 类适配器模式
- 继承了已存在的、具有特殊功能、但不符合我们既有的标准接口的类,实现了target,使得在不改变标准接口类和target关系的前提下,实现了通过target接口调用标准接口类的逻辑
- 对象适配器模式
- 不使用继承,而是在adapter类中直接声明被适配类。
- 观察者模式
- 通过Observable类(被观察者)和Observer接口(观察者)实现。
- 一个Observer对象监视着一个Observable对象的变化,当Observable对象发生变化时,Observer得到通知,就可以进行相应的工作。
- Observable中有setChanged()方法和notifyObservers()方法 / notifyObservers(Object data)方法,分别表示被观察者发生了变化和通知所有的或某个Observer变化完毕。
37. JNI的使用。
JNI技术的使用方法
- 定义:
- jni是一种协议,这个协议用来沟通java代码和外部的本地代码(c/c++),通过这个协议,java代码就可以调用外部的c++代码。
- 为何使用JNI
- 复用很多的c/c++代码。
- 提高程序的效率:java代码跨平台,不直接操作硬件;而c代码直接操作硬件。
- 使用步骤
- 编译过后,自动生成一个.so的动态链接库
- 在java代码中,把动态链接库加载到jvm虚拟机中加入一个静态代码块
- 像调用java代码一样,调用native方法;