牛客网错题总结集(一)

来源:互联网 发布:金牌网吧奖励软件 编辑:程序博客网 时间:2024/06/05 22:39
知识点:
1、StringBuilder reve=sub.reverse();反转内容
2、基本数据类型+""转为String
3、浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。
4、split默认是不会截取最后两个截取符中间的空值,若空值在中间,即String="a,b,,c"时则保留空值,使用split(",", -1)会保存空值,不会出现数组越界情况
5、PO、VO、BO、DTO、POJO、DAO之间的关系
PO:ersistant object持久对象
最形象的理解就是一个PO就是数据库中的一条记录。好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。
BO:business object业务对象
主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。比如一个简历,有教育经历、工作经历、社会关系等等。我们可以把教育经历对应一个PO,工作经历对应一个PO,社会关系对应一个PO。建立一个对应简历的BO对象处理简历,每个BO包含这些PO。这样处理业务逻辑时,我们就可以针对BO去处理。
VO :
value object值对象
ViewObject表现层对象
主要对应界面显示的数据对象。对于一个WEB页面,或者SWT、SWING的一个界面,用一个VO对象对应整个界面的值。
DTO :
Data Transfer Object数据传输对象主要用于远程调用等需要大量传输对象的地方
比如我们一张表有100个字段,那么对应的PO就有100个属性。但是我们界面上只要显示10个字段,客户端用WEB service来获取数据,没有必要把整个PO对象传递到客户端,这时我们就可以用只有这10个属性的DTO来传递结果到客户端,这样也不会暴露服务端表结构.到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO。
POJO :
plain ordinary java object 简单ava对象
个人感觉POJO是最参见最多变的对象,是一个中间对象,也是我们最常打交道的对象。一个POJO持久化以后就是PO
直接用它传递、传递过程中就是DTO,直接用来对应表示层就是VO。
DAO:
data access object数据访问对象
这个大家最熟悉,和上面几个O区别最大,基本没有互相转化的可能性和必要.主要用来封装对数据库的访问。通过它可以把POJO持久化为PO,用PO组装出来VO、DTO
6、volatile
用volatile修饰的变量,线程在每对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的
例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6,线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。
在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
package com.keyword;
public class TestWithoutVolatile {
private static boolean bChanged;
public static void main(String[] args) throws InterruptedException {
new Thread() {
@Override
public void run() {
for (;;) {
if (bChanged == !bChanged) {
System.out.println("!=");
System.exit(0);
}
}
}
}.start();
Thread.sleep(1);
new Thread() {
@Override
public void run() {
for (;;) {
bChanged = !bChanged;
}
}
}.start();
}
}
运行后,程序进入死循环了,一直在运行。
用volatile:
[java] view plain copy
package com.keyword;
public class TestWithVolatile {
private static volatile boolean bChanged;
public static void main(String[] args) throws InterruptedException {
new Thread() {
@Override
public void run() {
for (;;) {
if (bChanged == !bChanged) {
System.out.println("!=");
System.exit(0);
}
}
}
}.start();
Thread.sleep(1);
new Thread() {
@Override
public void run() {
for (;;) {
bChanged = !bChanged;
}
}
}.start();
}
}
程序输出!=,然后马上退出。
7.java中集合的继承体系


8.计算机读入写出的区别:
input 和out 是对计算机而言的,input是往计算机中输入,对计算机而言就是读,反之,out 就是从计算机往外输出 就是写 读进来,写出去。
9.线程唤醒通知
wait()、notify()和notifyAll()是 Object类 中的方法 ;
Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、 notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。
10.JDK1.6提供的6中垃圾回收器
11.substring 方法将返回一个包含从 start 到最后(不包含 end )的子字符串的字符串。
12.当试图在类方法(也就是静态方法)中调用类的非静态变量时,eclipse 给出了这么一句话 Cannot make a static reference to the non-static field xxx(xxx代表你所写的非静态域的名字)。这句话意思很简单,就是不能静态方法中引用非静态的域。
原因也很简单关于类初始化的过程中,静态域是随着类加载就完成了初始化,而非静态域此时都没有完成初始化,你引用它肯定就出错了。
13.关于Try-catch-finally
try-catch-finally 规则( 异常处理语句的语法规则 )
1) 必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。
2) 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
3) catch 块与相应的异常类的类型相关。
4) 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或 其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块
5) 可嵌套 try-catch-finally 结构。
6) 在 try-catch-finally 结构中,可重新抛出异常。
7) 除了下列情况,总将执行 finally 做为结束: JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击
由此可以看出,catch只会匹配一个,因为只要匹配了一个,虚拟机就会使整个语句退出
14.Boolean拆箱及if语句的赋值问题
Boolean修饰的变量为包装类型,初始化值为false,进行赋值时会调用Boolean.valueOf(boolean b)方法自动拆箱为基本数据类型,因此赋值后flag值为true,输出文本true。 如果使用==比较,则输出文本false。if的语句比较,除boolean外的其他类型都不能使用赋值语句,否则会提示无法转成布尔值。
15.静态变量只能在类主体中定义,不能在方法中定义
16.泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用add方 法,而<? super T>不能使用get方法,做为接口调用赋值时易出错。
说明: 扩展说一下PECS(Producer Extends Consumer Super)原则: 1)频繁往外读取内容的,适合用上界 Extends。 2)经常往里插入的,适合用下界 Super。
17.null可以被强制类型转换成任意类型(不是任意类型对象),于是可以通过它来执行静态方法。
18.Java一律采用Unicode编码方式,每个字符无论中文还是英文字符都占用2个字节。Java虚拟机中通常使用UTF-16的方式保存一个字符,ResourceBundle能够依据Local的不同,选择性的读取与Local对应后缀的properties文件,以达到国际化的目的。
19.有关forward和redirect
1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4.从效率来说
forward:高.
redirect:低.
20.关于加载器来说
1)Bootstrap ClassLoader
负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类
2)Extension ClassLoader
负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包
3)App ClassLoader
负责记载classpath中指定的jar包及目录中class
4)Custom ClassLoader
属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。
21.结构型设计模式
在GoF设计模式中,结构型模式有:
1.适配器模式 Adapter
适配器模式是将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。两个成熟的类需要通信,但是接口不同,由于开闭原则,我们不能去修改这两个类的接口,所以就需要一个适配器来完成衔接过程。
2.桥接模式 Bridge
桥接模式将抽象部分与它的实现部分分离,是它们都可以独立地变化。它很好的支持了开闭原则和组合锯和复用原则。实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这些多角度分离出来让他们独立变化,减少他们之间的耦合。
3.组合模式 Composite
组合模式将对象组合成树形结构以表示部分-整体的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
4.装饰模式 Decorator
装饰模式动态地给一个对象添加一些额外的职责,就增加功能来说,它比生成子类更灵活。也可以这样说,装饰模式把复杂类中的核心职责和装饰功能区分开了,这样既简化了复杂类,有去除了相关类中重复的装饰逻辑。 装饰模式没有通过继承原有类来扩展功能,但却达到了一样的目的,而且比继承更加灵活,所以可以说装饰模式是继承关系的一种替代方案。
5.外观模式 Facade
外观模式为子系统中的一组接口提供了同意的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式中,客户对各个具体的子系统是不了解的,所以对这些子系统进行了封装,对外只提供了用户所明白的单一而简单的接口,用户直接使用这个接口就可以完成操作,而不用去理睬具体的过程,而且子系统的变化不会影响到用户,这样就做到了信息隐蔽。
6.享元模式 Flyweight
享元模式为运用共享技术有效的支持大量细粒度的对象。因为它可以通过共享大幅度地减少单个实例的数目,避免了大量非常相似类的开销。享元模式是一个类别的多个对象共享这个类别的一个对象,而不是各自再实例化各自的对象。这样就达到了节省内存的目的。
7.代理模式 Proxy
为其他对象提供一种代理,并由代理对象控制对原对象的引用,以间接控制对原对象的访问。
22.volatile http://www.importnew.com/18126.html
//线程1
boolean stop = false;
while(!stop){
    doSomething();
}
//线程2
stop = true;
但是用volatile修饰之后就变得不一样了:
第一:使用volatile关键字会强制将修改的值立即写入主存;
第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
第三:由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取。
那么在线程2修改stop值时(当然这里包括2个操作,修改线程2工作内存中的值,然后将修改后的值写入内存),会使得线程1的工作内存中缓存变量stop的缓存行无效,然后线程1读取时,发现自己的缓存行无效,它会等待缓存行对应的主存地址被更新之后,然后去对应的主存读取最新的值。
那么线程1读取到的就是最新的正确的值。
23.子类构造方法在调用时必须先调用父类的,由于父类没有无参构造,必须在子类中显式调用,修改子类构造方法如下即可:
public Derived(String s){
super("s");
System.out.print("D");
}
24.AWT,抽象窗口工具包,是Java提供的建立图形用户界面的工具集,可用于生成现代的、鼠标控制的图形应用接口,且无需修改,就可以在各种软硬件平台上运行。
而swing是Java语言在编写图形用户界面方面的新技术,Swing采用模型-视图-控制设计范式,Swing可以使Java程序在同一个平台上运行时能够有不同外观以供用户选择。
两者不同在于一个是初代工具集,一个是进化版的工具集,用户不会再满足于初始的功能,而是更加注重于附加价值,明显从这点上,Swing是比AWT要好很多。
写法上,Swing的头文件引用包需要用到Javax,组件调用时也需要在AWT的基础上加上“J”。
25.full GC触发的条件
除直接调用System.gc外,触发Full GC执行的情况有如下四种。
1. 旧生代空间不足
旧生代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:
java.lang.OutOfMemoryError: Java heap space
为避免以上两种状况引起的FullGC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
2. Permanet Generation空间满
PermanetGeneration中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:
java.lang.OutOfMemoryError: PermGen space
为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。
3. CMS GC时出现promotion failed和concurrent mode failure
对于采用CMS进行旧生代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。
promotionfailed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。
应对措施为:增大survivorspace、旧生代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕后很久才触发sweeping动作。对于这种状况,可通过设置-XX:CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。
4. 统计得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间
这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。
例如程序第一次触发MinorGC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,则执行Full GC。
当新生代采用PSGC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否大于6MB,如小于,则触发对旧生代的回收。
除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。可通过在启动时通过- java-Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。
26.由于replaceAll方法的第一个参数是一个正则表达式,而"."在正则表达式中表示任何字符,所以会把前面字符串的所有字符都替换成"/"。如果想替换的只是".",那么久要写成"\\.".,
原创粉丝点击