Java,
Java,
1、输入Scanner input=new Scanner(System.in);
接受string类型:String str=new input.next();
接受int类型:int n=input.nextInt();
System.out.println(str);
System.out.println(n);
2、一维数组声明和定义方式:int a[]=new int[5]; int[] a=new int[5]; int[] a={1,2,3,4,5};
二维数组声明和定义方式:(1) int[][] a=new int [2][]; a[0]=new int[] {1,2}; (2) int[][] a={{1,2},{3,4}};
3、Java平台独立性
平台独立性指的是可以在一个平台上编写和编译程序,而在其他平台上执行。保证java具有该性质的是“中间码”和“Java虚拟机”(Java Virtual Machine,JVM)。Java程序被编译后不是生成能在硬件平台上执行的代码,而是生成一个“中间码”。不同平台上会安装有不同的JVM,由JVM负责把“中间码”翻译成硬件平台能执行的代码。由此看出JVM不具有平台独立性,而是与硬件平台有关。
而C/C++语言中,编译后的代码只能在特定的硬件上执行,换个硬件平台代码就无法执行了,从而也导致了C/C++没有跨平台的特性,但C/C++有更高的执行效率。
一个Java程序的运行从上到下的环境次序为:Java程序、JER/JVM、操作系统、硬件。
4、垃圾回收机制(Garbage Collection,GC)主要是回收程序中不再使用的内存。
Java中判断一个内存空间是否符合垃圾回收的标准有两个:(1)给对象赋予了空值null,以后再也没有使用过。(2)给对象赋予了新值,重新分配了内存空间。
一般来讲,内存泄露主要有两种情况:(1)在堆中申请的空间没有被释放;(2)对象已不再被使用,但还仍然在内存中保留着。(1)可用垃圾回收机制解决,对于(2),垃圾回收机制则无法保证不再使用的对象会被释放,因此Java中的内存泄露一般指的是情况(2)。
5、Java中的堆和栈
堆与栈都是内存中存放数据的地方。变量分为基本数据类型和引用类型。
基本数据类型(int ,short,long,char等)以及对象的引用变量,其内存都分配在栈上,变量出了作用域会自动释放,而引用类型的变量,其内存分配在堆上或者常量池(例如字符串常量和基本数据类型常量)中,需要通过new等方式进行创建。
具体而言,栈内存主要用来存放基本数据类型和引用变量。堆内存用来存放运行时创建的对象。
6、HashMap
Java为数据结构中的映射定义了一个接口java.util.Map,它包括3个实现类:HashMap、HashTable和TreeMap。Map是用来存储键值对的数据结构,在数组中通过数组下标来对其内容索引的,而在Map中,则是通过对象来进行索引,用来索引的对象叫做key,其对应的对象叫做value。
HashMap是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
7、HashMap、Hashtable、TreeMap和WeekHashMap的区别
HashMap是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。因为HashMap和Hashtable都采用了hash法进行索引,因此二者具有许多相似之处,它们主要有如下的一些区别:
1)HashMap是Hashtable的轻量级实现(非线程安全的实现),它们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key)(但需要注意,最多只允许一条记录的键为null,不允许多条记录的值为null),而Hashtable不允许。
2)HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey,因为contains方法容易让人引起误解。Hashtable继承自Dictionary类,而HashMap是java 1.2引进的Map interface的一个实现。
3)Hashtable的方法是线程安全的,而HashMap不支持线程的同步,所以它不是线程安全的。在多个线程访问Hashtable时,不需要开发人员对它进行同步,而对于HashMap,开发人员必须提供额外的同步机制。所以,就效率而言,HashMap可能高于Hashtable。
4)Hashtable使用Enumeration,HashMap使用Iterator。
5)Hashtable和HashMap采用的hash/rehash算法都几乎一样,所以性能不会有很大的差异。
6)在Hashtable中,hash数组默认大小是11,增加的方式是old×2+1。在HashMap中,hash数组的默认大小是16,而且一定是2的指数。
7)hash值的使用不同,Hashtable直接使用对象的hashCode。
TreeMap实现了SortMap接口,能够把它保存的记录根据键排序,因此,取出来的是排序后的键值对,如果需要按自然顺序或自定义的顺序遍历键,那么TreeMap更好。LinkedHashMap是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排序。
WeakHashMap与HashMap类似,二者的不同之处在于,WeekHashMap中的key采用的是“弱引用”的方式,只要WeekHashMap中的key不再被外部引用,它就可以被垃圾回收器回收。而HashMap中key采用的是“强引用”的方式,当HashMap中的key没有被外部引用时,只有在这个key从HashMap中删除后,才可以被垃圾回收器回收。
在Hashtable上下文中,同步指的是什么?
答案:同步意味着在一个时间点只能有一个线程可以修改hash表,任何线程在执行Hashtable的更新操作前都需要获取对象锁,其他线程则等待锁的释放。
如何实现HashMap的同步?
答案:HashMap可以通过Map m=Collections.sychronizedMap( new HashMap())来达到同步的效果。具体而言,该方法返回一个同步的Map,该Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。
hashtable 实现了enumeration 不支持 fail-fast 但加了同步 ,操作都是线程安全的 但是慢
hashmap 实现了Iterator 支持了 fail-fast 没有加同步,操作都是线程不安全的 会快些
单线程hashmap 效率高 多线程hashmap 可能会抛出异常
“快速失败”也就是fail-fast,它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。是有可能而不是一定。例如:假设存在两个线程1和2,线程1通过iterator在遍历集合A中的元素,在某个时刻线程2修改了集合A的结构(是结构上的修改,而不是简单的修改集合元素的内容),那么这个时候程序会抛出CurrentModificationException异常,从而产生fail-fast机制。
8、线程和进程
线程是指程序在执行过程中,能够执行程序代码的一个执行单元。线程分为四种状态:运行、就绪、挂起和结束。
进程是指一段正在执行的程序,而线程有时也被称为轻量级进程,它是程序执行的最小单元,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间(代码段、数据段和堆空间)及一些进程级的资源(例如打开的文件),但是各个线程拥有自己的栈空间。
在操作系统级别上,程序的执行是以进程为单位的,而每个进行中通常都会有多个线程互不影响地并发执行。多线程的好处:
(1)使用多线程可以减少程序的响应时间。
(2)与进程相比,线程的创建和切换开销更小。
(3)多CPU或多核计算机本身就具有多线程的能力,如果使用单个线程,将无法重复利用计算机资源,造成资源的巨大浪费。因此使用多线程可以提高CPU的利用率。
(4)使用多线程能简化程序的结构,使程序便于理解和维护。一个非常复杂的进程可以分成多个线程来执行。
9、同步和异步
在多线程的环境中,当多个线程需要访问同一个资源时,需要以某种顺序来保证该资源在某一时刻只能被一个线程使用,否则程序的运行结果将会是不可预料的,在这种情况下就必须对数据进行同步,例如多个线程同时对统一数据进行写操作,即当线程A需要使用某个资源时,如果这个资源正在被线程B使用,同步机制就会让线程A一直等待下去,直到线程B结束对该资源的使用后,线程A才能使用这个资源,由此可见,同步机制能够保证资源的安全。
要想实现同步操作,必须要获得每一个线程对象的锁。获得它可以保证同一时刻只有一个线程能够进入临界区(访问互斥资源的代码块),并且在这个锁被释放之前,其他线程就不能再进入这个临界区。如果还有其他线程想要获得该对象的锁,只能进入等待队列等待。只有当拥有该对象锁的线程退出临界区时,锁才会被释放,等待队列中优先级最高的线程才能获得该锁,从而进入代码共享代码区。Java中可以通过synchronized关键字来实现同步,它是以很大的系统开销作为代价的,有时候甚至可能造成死锁,所以同步控制并非越多越好,要尽量避免无谓的同步控制。实现同步的方式有两种:一种是利用同步代码块实现同步;另一种是利用同步方法来实现同步。
异步与非阻塞类似,由于每个线程都包含了运行时自身所需要的数据或方法,因此在进行输入输出处理时,不必关心其他进程的状态行为,也不必等到输入输出处理完毕才返回。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,异步能够提高程序的效率。
举个简单的例子区分同步和异步。同步就是你喊我去吃饭,如果听到了,我就和你去吃饭;如果我没有听到,你就不停地喊,直到我告诉你听到了,我们才一起去吃饭。异步就是你喊我,然后自己去吃饭,我得到消息后可能立即走,也可能得到下班才去吃饭。
10、如何实现Java多线程
(1)继承Thread类,重写run()方法
Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且启动线程的唯一方法就是通过Thread类的start()方法。start()方法是一个native(本地)方法,它将启动一个新线程,并执行run()方法(Thread中提供的run()方法是一个空方法)。这种方式通过自定义直接extend Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法。需要注意的是,调用start()方法后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行多线程代码是由操作系统决定的。Thread的使用方法如下:
class MyThread extends Thread{
public void run(){
System.out.println("Thread body");//线程的函数体
}
}
public class Test{
public static void main(String[] args){
MyThread thread=new MyThread();
thread.start();//开启线程
}
}
(2)实现Runnable接口,并实现接口的run()方法
以下是主要步骤:
1)自定义类并实现Runnable接口,实现run()方法。
2)创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象。
3)调用Thread的start()方法。
class MyThread implements Runnable{
public void run(){
System.out.println("Thread body");//线程的函数体
}
}
public class Test{
public static void main(String[] args){
MyThread thread=new MyThread();
Thread t=new Thread(thread);
t.start();//开启线程
}
}
其实,不管是通过继承Thread类还是通过使用Runnable接口来实现多线程的方法,最终还是通过Thread的对象的API来控制线程的。
(3)实现Callable接口,重写call()方法
Callable接口实际是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更强大的功能,主要表现为以下3点:
1)Callable可以在任务结束后提供一个返回值,Runnable无法提供这个功能。
2)Callable中的call()方法可以抛出异常,而Runnable的run()方法不能抛出异常。
3)运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,它提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下,就可以用Future来监视目标线程调用call()方法的情况,当调用Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法结束返回结果。
以上3种方式中,前两种方式线程执行完成后都没有返回值,只有最后一个是带返回值的。当需要实现多线程时,一般推荐实现Runnable接口的方式,其原因是:首先Thread类定义了多种方法可以被派生类使用或重写。但是只有run()方法是必须被重写的,在run()方法中实现这个线程的主要功能。这当然是实现Runnable接口所需的方法。其次,很多Java开发人员认为,一个类仅在他们需要被加强或修改时才会被继承。因此,如果没有必要重写Thread类中的其他方法,那么通过继承Thread的实现方式与实现Runnable接口的效果相同,在这种情况下最好通过实现Runnable接口的方式创建线程。另外Java中类的继承方式是单继承,不支持多继承,若继承Thread类实现多线程,可能无法继续继承其他类。
11、多线程同步的实现方法有哪些
当使用多线程访问一个资源时,非常容易出现线程安全问题。(例如,当多个线程同时对一个数据进行修改时,会导致某些线程对数据的修改丢失)。因此,需要采用同步机制来解决这种问题。Java主要提供了3种实现同步机制的方法:
(1)sychronized关键字
在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程所拥有,当一个线程调用对象的一段sychronized代码时,需要先获取这个锁,然后去执行相应的代码,执行结束后,释放锁。
sychronized关键字主要有两种用法(sychronized方法和sychronized块),此外该关键字还可以作用于静态方法、类或某个实例,但这都对程序的效率有很大的影响。
1)sychronized方法。在方法的声明前加入sychronized关键字,示例如下:
public sychronized void mutiThreadAccess();
主要把多个线程对类需要被同步的资源放到 mutiThreadAccess()方法中,就能保证这个方法在同一时刻只能被一个线程访问,从而保证了多线程访问的安全性。然而,当一个方法的方法体规模非常大时,把该方法声明为sychronized会大大影响程序的执行效率。为了提高程序的效率,Java提供了synchronized块。
2)sychronized块。synchronized块既可以把任意的代码段声明为synchronized,也可以指定上锁的对象,有非常高的灵活性。其用法如下:
synchronized(syncObject){
//访问syncObject的代码
}
(2)wait()方法和notify()方法
当使用sychronized来修饰某个共享资源时,如果线程A1在执行synchronized代码,另外一个线程A2也要同时执行同一对象的同一synchronized代码时,线程A2将要等到线程A1执行完成时,才能继续执行。在这种情况下可以使用wait()方法和notify()方法。
在sychronized代码被执行期间,线程可以调用wait()方法,释放对象锁,进入等待状态,并且可以调用notify()方法或notifyAll()方法通知正在等待的其他线程。notify()方法仅唤醒一个线程(等待队列的第一个线程)并允许它去获得锁,notifyAll()方法唤醒所有等待这个对象的线程并允许他们去获得锁(并不是让所有唤醒线程获取到锁,而是让它们去竞争)。
(3)Lock
JDK5新增加了Lock接口以及它的一个实现类ReentrantLock(重入锁),Lock也可以用来实现多线程的同步,具体而言,它提供了如下一些方法来实现多线程的同步:
1)lock()。以阻塞的方式获取锁,也就是说,如果获取到了锁,立即返回;如果别的线程持有锁,当前线程等待,直到获取锁后返回。
2)tryLock()。以非阻塞的方式获取锁。只是尝试性地去获取一下锁,如果获取到锁,立即返回true,否则,立即返回false。
3)tryLock(long timeout, TimeUnit unit)。如果获取了锁,立即返回true,否则会等待参数给定的时间单元,在等待的过程中,如果获取了锁,就返回true,如果等待超时,返回false。
4)lockInterruptibly()。如果获取了锁,立即返回;如果没有获取锁,当前线程处于休眠状态,直到获得锁,或者当前线程被别的线程中断(会收到InterruptedException异常)。它与lock()方法最大的区别在于如果lock()方法获取不到锁,会一直处于阻塞状态,且会忽略interrupt()方法。
12、synchronized与Lock有什么异同
Java提供了两种锁机制来实现对某个共享资源的同步:synchronized和Lock。其中,synchronized使用Object对象本身的notify、wait、notityAll调度机制,而Lock可以使用Condition进行线程之间的调度,完成synchronized实现的所有功能。
二者的主要区别如下:
1)用法不一样。在需要同步的对象中加入synchronized控制,synchronized既可以加在方法上,也可以加在特定代码块中,括号中表示要锁的对象。而Lock需要显示地指定起始位置和终止为止。synchronized是托管给JVM执行的,而Lock的锁定是通过代码实现的,它有比synchronized更精确的线程语义。
2)性能不一样。在资源竞争不是很激烈的情况下,synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,synchronized的性能下降得非常快,而ReetrantLock的性能基本保持不变。
3)锁机制不一样。synchronized获得锁和释放的方式是在块结构中,当获取多个锁时,必须以相反的顺序释放,并且是自动解锁,不会因为出了异常而导致锁没有被释放从而引发死锁。而Lock则需要开发人员手动去释放,并且必须在finally块中释放,否则会引起死锁问题的发生。此外,Lock还提供了更强大的功能,它的tryLock()方法可以采用非阻塞的方式去获取锁。
13、单例模式
public class Test{
private Test(){}
private static Test t=new Test();
public static Test getT(){
return t;
}
}
14、
public的类、类属变量及方法,包内及包外的任何类均可以访问;
protected的类、类属变量及方法,包内的任何类,及包外的那些继承了此类的子类才能访问;
private的类、类属变量及方法,包内包外的任何类均不能访问;
如果一个类、类属变量及方法不以这三种修饰符来修饰,那么包内的任何类都可以访问它,而包外的任何类都不能访问它(包括包外继承了此类的子类),因此,这类、类属变量及方法对包内的其他类是友好的,开放的,而对包外的其他类是关闭的。
相关文章
- 暂无相关文章
用户点评