java学习必看,面试问题及java写代码注意事项

平时写代码时需要注意的:面试也会经常问到的

1:string stringbuffer,stringbuilder的区别,什么时候用最好!

2:list,set,map 都在什么时候用最好!

3:定义静态变量和常量用在什么时候定义最好!

4:int ,integer ,long,Long 类似这种常量和对像在什么时候用!

5:数据库事务的管理机制,怎么去管理

6:理解下java机制,在什么时候用什么!

 

思考下,你是否都会回答出来。

以下是答案,及平时写代码时,需要注意的事项。

 

(1)如果要操作少量的数据用String

(2)单线程操作字符串缓冲区下操作大量数据用StringBuilder

(3)多线程操作字符串缓冲区下操作大量数据用StringBuffer

 

 

list 是列表 是顺序存放对象的,可以有相同的对象,通过索引存取。非线程安全,list想实现线程安全可以用Vector.

1:次序是List最重要的特点:它保证维护元素特定的顺序。

2:ArrayList : 由数组实现的List。允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。Iterator只应该用来由后向前遍历ArrayList,而不是用来插入和移除元素。因为那比LinkedList开销要大很多。

3:Vector -线程安全的,这两个类底层都是由数组实现的,效率低  比较简单和ArrayList差不多,主要是内部实现了synchronized关键字,实现了线程安全访问但性能有些降低,同时对于元素的扩充在算法上和ArrayList稍有不同,通过构造的容量增量系数来决定。 

4:LinkedList : 对顺序访问进行了优化,向List中间插入与删除的开销并不大。随机访问则相对较慢。(使用ArrayList代替。)还具有下列方法:addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 这些方法 (没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。线程非安全,为双向链表结构,

1.ArrayList是基于数组,LinkedList基于链表实现(涉及到指针)。 

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 

4.查找操作indexOf,lastIndexOf,contains等,两者差不多。 

 

set 集合 无序存放对象的,其中不能有重复的对象 集合没有索引,只能遍历次存取;非线程安全。

1:存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。 

2:HashSet : 为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。

   3:TreeSet : 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。 

  4:LinkedHashSet : 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。

 

map 映射 存放的是键与值的映射,其中键是唯一的(不能有重复对象),而值可以有重复的对象,存的时候,需要指定键和对应的值,取的时候可以根据键名取到值,也可以遍历。非线程安全。想实现线程安全就实用hashTable。

1:执行效率是Map的一个大问题。看看get()要做哪些事,就会明白为什么在ArrayList中搜索“键”是相当慢的。而这正是HashMap提高速度的地方。HashMap使用了特殊的值,称为“散列码”(hash code),来取代对键的缓慢搜索。“散列码”是“相对唯一”用以代表对象的int值,它是通过将该对象的某些信息进行转换而生成的。所有Java对象都能产生散列码,因为hashCode()是定义在基类Object中的方法。  

2:HashMap就是使用对象的hashCode()进行快速查询的。此方法能够显著提高性能。Map : 维护“键值对”的关联性,使你可以通过“键”查找“值”  Map基于散列表的实现。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量capacity和负载因子load factor,以调整容器的性能。

3:LinkedHashMap : 类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,因为它使用链表维护内部次序。   

4:TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。TreeMap的特点在于,你得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。   

5:WeakHashMao : 弱键(weak key)Map,Map中使用的对象也被允许释放: 这是为解决特殊问题设计的。如果没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。   

6:IdentifyHashMap : 使用==代替equals()对“键”作比较的hash map。专为解决特殊问题而设计。

按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。

 

 

区别在于:

常量本身就是值的形式,内存中是不分空间的 。常量是存在于方法区的常量区,类没加载的时候也可以使用

而静态变量,是变量形式,内存中是要分空间的,静态变量是属于类的,它是拥有的一个存储空间。

 

int是JAVA八大基本数据类型(byte,shor,int,long,char,boolean,float,double)之一。 JAVA语言为八大基本数据提供了包装类,Integer对应是int类型的包装类,就是把int类型包装成Object对象。 Java有2种不同的类型:引用类型和原始类型。Int是java的原始数据类型,Integer是java的为int提供的封装类。Java为每个原始类型提供了封装类。当引用类型和原始类型用作某个类的实例时所指定的缺省值。对象引用实例变量的缺省值为null,而原始类型实例变量的缺省值与它们的类型有关。

int和integer对(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比

 

 

1.  并发控制的单位――事务

事务应该具有4种属性:原子性、一致性、隔离性和持久性。

2. 并发操作与数据的不一致性

并发操作带来的数据库不一致性可以分为四类:丢失或覆盖更新、脏读、不可重复读和幻像读

了保证事务的隔离性与一致性,就有了数据库的锁机制。

在数据库中,存在着很多种类的锁:共享锁、排他锁、悲观锁、乐观锁、行级锁、表级锁等。

  • 共享锁只用于表级,排它锁用于行级或表级。
  • 加了共享锁的对象,可以继续加共享锁,不能再加排他锁。
  • 加了排他锁的对象,不能再加任何锁。

 

Spring对事务的解决办法其实分为2种:编程式实现事务,AOP配置声明式解决方案。 

Spring提供两种编程式事务支持:直接使用PlatformTransactionManager实现和使用TransactionTemplate模板类,用于支持逻辑事务管理。 

声明式事务,最常用的两种方法是 tx:Advice 和 tx:annotation-driven 两种方式。两种方式的配置文件解析器分别

注解形式@Transactional实现事务管理 

是: org.springframework.transaction.config.TxAdviceBeanDefinitionParser 和 org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser 

注意@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。 

 

①首先采用通用的java编译器将java源程序编译成为与平台无关的字节码文件(class文件)

②然后由java虚拟机(JVM)对字节码文件解释执行。

2.2 JVM(Java Virtual Machine Java虚拟机)

(1)JVM是Java字节码执行的引擎,为java程序的执行提供必要的支持,还能优化java字节码,使之转换成效率更高的机器指令。程序员编写的程序最终都要在JVM上执行,JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的。  (2)ClassLoader是java运行时一个重要的系统组件,负责在运行时查找和装入类文件的类。

(3)JVM屏蔽了与具体操作系统平台相关的信息,从而实现了java程序只需生成在JVM上运行的字节码文件(class文件),就可以在多种平台上不加修改地运行。不同平台对应着不同的JVM,在执行字节码时,JVM负责将每一条要执行的字节码送给解释器,解释器再将其翻译成特定平台环境的机器指令并执行。java语言最重要的特点就是跨平台运行,使用JVM就是为了支持与操作系统无关,实现跨平台运行。

 

2.3 ClassLoader

(1)是JVM实现的一部分,包括bootstrapclassloader(启动类加载器)

(2)ClassLoader在JVM运行的时候加载java核心的API,通过java程序实现两个ClassLoader:

①ExtClassLoader,它的作用是用来加载java的扩展API,也就是lib\ext类;

②AppClassLoader,用来加载用户机器上CLASSPATH设置目录中的Class.

(3)ClassLoader加载流程:当运行一个程序的时候,JVM启动,运行bootstrapclassloader,该ClassLoader加载java核心API,然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class.

 

2.4JRE

JRE是JavaRuntimeEnvironment,java运行时环境,它是java程序运行所必须的环境集合,主要由java虚拟机、java平台核心类和若干支持文件组成。其不包含开发工具、编译器、调试器以及其他工具。

在执行java程序的时候,操作系统会按照下面顺序寻找JRE环境。

(1)先查找当前目录下有没有JRE

(2)再查找父目录下有没有JRE

(3)接着在环境变量PATH制定的路径中查找JRE

(4)注册表查看CurrentVersion的键值指向哪个JRE

JRE自带的基础类库主要在JRE\LIB\rt.jar文件中。在程序运行时,JRE由ClassLoader(类加载器)负责查找和加载程序引用到的基类库和其他类库。基础类库,Classloader会自动到rt.jar的位置;其他的类库,ClassLoader在环境变量CLASSPATH制定的路径中搜索。

 

2.5 JDK

JDK是Java Development Kit,简称java开发工具包。

JDK是java的核心。它包括java运行环境、一堆java工具盒java基础的类库(rt.jar)。

JDK包含JRE的全部内容外,还包含开发者用以编译、调试和运行java程序的工具。

JDK、JRE、JVM之间的关系:

JDK、JRE、JVM之间是包含关系。范围由大到小依次为JDK、JRE、JVM。

 

Java虚拟机执行过程有三个典型特点:

 

(1)多线程:Java虚拟机支持多个线程的同时运行,这些线程独立的执行Java代码,处理公共数据区和私有栈中的数据。

 

(2)动态连接:Java程序之所以适合在网络上运行,其主要原因是由于Java虚拟机具有动态连接特性。

 

(3)异常处理:Java虚拟机提供了可靠的异常处理

 

 

springmvc 中,后台获取rquest的方法。

java获取request对象

ActionContext ctx = ActionContext.getContext();

HttpServletRequest request = (HttpServletRequest)ctx.get(ServletActionContext.HTTP_REQUEST);

Java获取response对象

HttpServletResponse response = ServletActionContext.getResponse();

HttpServletRequest request =((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();

 

平时写代码需要注意:

 

在java 中 定义路径时,加/与不加,路径差别很大。

string path = "/opt/*";表示在classpath项目下的根目录下。

String path = “opt/”;表示在当前类加载的路径下。

 

user.getName().equals("xiaoming"); //有经验的老司机很快就能看到问题,如果user.getName()为null,就会抛出空指针异常,因此下面的写法更为稳妥 "xiaoming".equals(user.getName()); //当然这种写法并不是万能的,如果比对的两边都是未知变量,如下

 

Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; System.out.println(a == b);// 结果为:true System.out.println(c == d);// 结果为:false

IntegerCache.low默认为-128,high默认为127(可调整)。

  这样a=b就很好解释了,因为==比较的是内存地址,a,b都是从这个缓存类中取的同一个对象,所以返回结果为true。b,c则都是new的新对象,内存地址自然不同,所以返回false。

 

String的getBytes()方法用的是当前项目的默认编码,如果不指定编码,在不同的运行环境很容易被坑,所以还是根据自己的需要指定对应的编码比较靠谱

String str="韦德"; byte[] bytes = str.getBytes("utf-8");

 

list.toArray

List<String> list = new ArrayList<String>(); String[] array=(String[]) list.toArray();

  上面的写法乍一看似乎没有什么问题,但list.toArray()返回的是一个object数组,强转会抛异常。其实是可以指定返回数组的类型的,如下

String[] array=list.toArray(new String[list.size()]);

 

Arrays.asList(array)

String [] array= {"a","b","c"}; // 返回的List实例为:java.util.Arrays.ArrayList List<String> list = Arrays.asList(array); list.remove(0);

  Arrays.asList是一种很常见的创建List的方式,但该方法返回的List实例不是平时常用的List实例,而是Arrays的一个静态内部类,该类继承自AbstractList类,并未提供List的完整的实现,例如remove方法就未实现。当然,如果只是用做遍历,则完全是没问题的。

  类似的情况还有不少,使用时要注意,例如:

1、ArrayList的subList方法,返回的是ArrayList中的一个内部类java.util.ArrayList.SubList

2、HashMap的values方法,返回的是HashMap中的一个内部类:java.util.HashMap.Values

 

 

将css放在html页面的顶部,而把js放在html页面的底部

1.尽量指定类的final修饰符 带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了人们覆盖length()方法。另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50% 。

2.尽量重用对象。特别是String 对象的使用中,出现字符串连接情况时应用StringBuffer 代替。由于系统不仅要花时间生成对象,以后可能还需花时间对这些对象进行垃圾回收和处理。因此,生成过多的对象将会给程序的性能带来很大的影响。

3.尽量使用局部变量,调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。请参见《尽可能使用堆栈变量》。

4.不要重复初始化变量  默认情况下,调用类的构造函数时, Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和double变量设置成0.0,逻辑值设置成false。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键词创建一个对象时,构造函数链中的所有构造函数都会被自动调用。

5.在JAVA + ORACLE 的应用系统开发中,java中内嵌的SQL语句尽量使用大写的形式,以减轻ORACLE解析器的解析负担。

6. Java 编程过程中,进行数据库连接、I/O流操作时务必小心,在使用完毕后,即使关闭以释放资源。因为对这些大对象的操作会造成系统大的开销,稍有不慎,会导致严重的后果。

7.由于JVM的有其自身的GC机制,不需要程序开发者的过多考虑,从一定程度上减轻了开发者负担,但同时也遗漏了隐患,过分的创建对象会消耗系统的大量内存,严重时会导致内存泄露,因此,保证过期对象的及时回收具有重要意义。JVM回收垃圾的条件是:对象不在被引用;然而,JVM的GC并非十分的机智,即使对象满足了垃圾回收的条件也不一定会被立即回收。所以,建议我们在对象使用完毕,应手动置成null。

8.在使用同步机制时,应尽量使用方法同步代替代码块同步。

9.尽量减少对变量的重复计算

10.尽量采用lazy loading 的策略,即在需要的时候才开始创建。

11.慎用异常 

异常对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。 异常只能用于错误处理,不应该用来控制程序流程。

 

11.慎用异常 

异常对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。 异常只能用于错误处理,不应该用来控制程序流程。

12.不要在循环中使用Try {

} catch() {

应把其放置在最外层

 

13.StringBuffer 的使用:

        StringBuffer表示了可变的、可写的字符串。

有三个构造方法 :

Java代码  

1.StringBuffer ();            //默认分配16个字符的空间   

2.StringBuffer (int size);  //分配size个字符的空间   

3.StringBuffer (String str);  //分配16个字符+str.length()个字符空间   

StringBuffer ();            //默认分配16个字符的空间

StringBuffer (int size);  //分配size个字符的空间

StringBuffer (String str);  //分配16个字符+str.length()个字符空间 

14.合理的使用Java类 java.util.Vector。

简单地说,一个Vector就是一个java.lang.Object实例的数组。Vector与数组相似,它的元素可以通过整数形式的索引访问。但是,Vector类型的对象在创建之后,对象的大小能够根据元素的增加或者删除而扩展、缩小

15.当复制大量数据时,使用System.arraycopy()命令。

16.代码重构:增强代码的可读性。

 

17.不用new关键词创建类的实例 

用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。clone()方法不会调用任何类构造函数。 

在使用设计模式(Design Pattern)的场合,如果用Factory模式创建对象,则改用clone()方法创建新的对象实。

18.乘法和除法 用移位操作替代乘法操作可以极大地提高性能

 

19.在JSP页面中关闭无用的会话。

    一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <%@page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。

对于那些无需跟踪会话状态的页面,关闭自动创建的会话可以节省一些资源。使用如下page指令:<%@ page session="false"%>

20.JDBC与I/O 

如果应用程序需要访问一个规模很大的数据集,则应当考虑使用块提取方式。默认情况下,JDBC每次提取32行数据。举例来说,假设我们要遍历一个5000行的记录集,JDBC必须调用数据库157次才能提取到全部数据。如果把块大小改成512,则调用数据库的次数将减少到10次。

 

21.Servlet与内存使用 

许多开发者随意地把大量信息保存到用户会话之中。一些时候,保存在会话中的对象没有及时地被垃圾回收机制回收。从性能上看,典型的症状是用户感到系统周期性地变慢,却又不能把原因归于任何一个具体的组件。如果监视JVM的堆空间,它的表现是内存占用不正常地大起大落。

解决这类内存问题主要有二种办法。第一种办法是,在所有作用范围为会话的Bean中实现HttpSessionBindingListener接口。这样,只要实现valueUnbound()方法,就可以显式地释放Bean使用的资源。 另外一种办法就是尽快地把会话作废。大多数应用服务器都有设置会话作废间隔时间的选项。另外,也可以用编程的方式调用会话的setMaxInactiveInterval()方法,该方法用来设定在作废会话之前,Servlet容器允许的客户请求的最大间隔时间,以秒计。

22、使用缓冲标记 

一些应用服务器加入了面向JSP的缓冲标记功能。例如,BEA的WebLogic Server从6.0版本开始支持这个功能,Open Symphony工程也同样支持这个功能。JSP缓冲标记既能够缓冲页面片断,也能够缓冲整个页面。当JSP页面执行时,如果目标片断已经在缓冲之中,则生成该片断的代码就不用再执行。页面级缓冲捕获对指定URL的请求,并缓冲整个结果页面。对于购物篮、目录以及门户网站的主页来说,这个功能极其有用。对于这类应用,页面级缓冲能够保存页面执行的结果,供后继请求使用。

23、选择合适的引用机制

在典型的JSP应用系统中,页头、页脚部分往往被抽取出来,然后根据需要引入页头、页脚。当前,在JSP页面中引入外部资源的方法主要有两种:include指令,以及include动作。 

include指令:例如<%@ include file="copyright.html" %>。该指令在编译时引入指定的资源。在编译之前,带有include指令的页面和指定的资源被合并成一个文件。被引用的外部资源在编译时就确定,比运行时才确定资源更高效。 

include动作:例如<jsp:include page="copyright.jsp" />。该动作引入指定页面执行后生成的结果。由于它在运行时完成,因此对输出结果的控制更加灵活。但时,只有当被引用的内容频繁地改变时,或者在对主页面的请求没有出现之前,被引用的页面无法确定时,使用include动作才合算。

24、及时清除不再需要的会话 

为了清除不再活动的会话,许多应用服务器都有默认的会话超时时间,一般为30分钟。当应用服务器需要保存更多会话时,如果内存容量不足,操作系统会把部分内存数据转移到磁盘,应用服务器也可能根据“最近最频繁使用”(Most Recently Used)算法把部分不活跃的会话转储到磁盘,甚至可能抛出“内存不足”异常。在大规模系统中,串行化会话的代价是很昂贵的。当会话不再需要时,应当及时调用HttpSession.invalidate()方法清除会话。HttpSession.invalidate()方法通常可以在应用的退出页面调用。

25、不要将数组声明为:public static final 。

26、HashMap的遍历用合适的方式。

27、array(数组) 和 ArryList的使用

array([]):最高效;但是其容量固定且无法动态改变;

ArrayList:容量可动态增长;但牺牲效率;

基于效率和类型检验,应尽可能使用array,无法确定数组大小时才使用ArrayList!

ArrayList是Array的复杂版本

ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。

ArrayList存入对象时,抛弃类型信息,所有对象屏蔽为Object,编译时不检查类型,但是运行时会报错。

28、尽量使用HashMap 和ArrayList ,除非必要,否则不推荐使用HashTable和Vector ,后者由于使用同步机制,而导致了性能的开销。

 

如果觉得文章真心好, 请打赏下我吧,程序员赚钱不容易。 十块八块不嫌多, 一块两块也是爱啊! 谢谢大家支持!

                              

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值