javaee论坛

普通会员

225649

帖子

65

回复

79

积分

楼主
发表于 2019-10-30 15:44:42 | 查看: 110 | 回复: 1

我们有时候将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象。例如,要将java对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个java对象变成某个格式的字节流再传输。但是,jre本身就提供了这种支持,我们可以调用OutputStream的writeObject方法来做,如果要让java帮我们做,要被传输的对象必须实现serializable接口。这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化。需要被序列化的类必须实现Serializable接口,该接口是一个mini接口,其中没有需要实现的方法,implementsSerializable只是为了标注该接口的对象是可被序列化的。例如,在web开发中,如果对象被保存在了Session中,tomcat在重启时要把Session对象序列化到硬盘,这个对象就必须实现Serializable接口。如果对象要经过分布式系统进行网络传输或通过rmi等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Serializable接口。

2、描述一下JVM加载class文件的原理机制?

JVM中类的装载是由ClassLoader和它的子类来实现的,JavaClassLoader是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。

3、heap和stack有什么区别。

java的内存分为两类,一类是栈内存,一类是堆内存。栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用new创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用final修饰后,放在堆中,而不是栈中。

4、GC是什么?为什么要有GC?

GC是垃圾收集的意思(GabageCollection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。

5、垃圾回收的优点和原理。并考虑2种回收机制。

Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

6、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

7、什么时候用assert。

assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,assert将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion检查通常是关闭的。

publicstaticvoidmain(String[]args){//TODOAuto-generatedmethodstubinti=0;for(i=0;i<5;i++){System.out.println(i);}//假设程序不小心多了一句--i;--i;asserti==5;}8、java中会存在内存泄漏吗,请简单描述。

所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Java使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的,例如下面的代码可以看到这种情况的内存回收:

publicclassGarbageTest{publicstaticvoidmain(String[]args)throwsIOException{try{gcTest();}catch(IOExceptione){e.printStackTrace();}System.out.println("hasexitedgcTest!");System.in.read();System.in.read();System.out.println("outbegingc!");for(inti=0;i<100;i++){System.gc();System.in.read();System.in.read();}}privatestaticvoidgcTest()throwsIOException{System.in.read();System.in.read();Personp1=newPerson();System.in.read();System.in.read();Personp2=newPerson();p1.setMate(p2);p2.setMate(p1);System.out.println("beforeexitgctest!");System.in.read();System.in.read();System.gc();System.out.println("exitgctest!");}privatestaticclassPerson{byte[]data=newbyte[20000000];Personmate=null;publicvoidsetMate(Personother){mate=other;}}}

java中的内存泄露的情况:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中可能出现内存泄露的情况,例如,缓存系统,我们加载了一个对象放在缓存中(例如放在一个全局map对象中),然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。检查java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。

如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。

下面内容来自于网上(主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中拿掉,而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让它从数组中消失,将那个元素所在的位置的值设置为null即可):我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子不是我想到的,是书上看到的,当然如果没有在书上看到,可能过一段时间我自己也想的到,可是那时我说是我自己想到的也没有人相信的。

publicclassStack{privateObject[]elements=newObject[10];privateintsize=0;publicvoidpush(Objecte){ensureCapacity();elements[size++]=e;}publicObjectpop(){if(size==0)thrownewEmptyStackException();returnelements[--size];}privatevoidensureCapacity(){if(elements.length==size){Object[]oldElements=elements;elements=newObject[2*elements.length+1];System.arraycopy(oldElements,0,elements,0,size);}}}上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无用,无法回收。但是就是存在这样的东西也不一定会导致什么样的后果,如果这个堆栈用的比较少,也就浪费了几个K内存而已,反正我们的内存都上G了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。下面看两个例子。例子1publicclassBad{publicstaticStacks=Stack();static{s.push(newObject());s.pop();//这里有一个对象发生内存泄露s.push(newObject());//上面的对象可以被回收了,等于是自愈了}}

因为是static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的Stack最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很容易理解,Stack内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!

内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。

9、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?

字节流,字符流。字节流继承于InputStreamOutputStream,字符流继承于Reader和Writer。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。

10、字节流与字符流的区别要把一片二进制数据数据逐一输出到某个设备中,或者从某个设备中逐一读取一片二进制数据,不管输入输出设备是什么,我们要用统一的方式来完成这些操作,用一种抽象的方式进行描述,这个抽象描述方式起名为IO流,对应的抽象类为OutputStream和InputStream,不同的实现类就代表不同的输入和输出设备,它们都是针对字节进行操作的。在应用中,经常要完全是字符的一段文本输出去或读进来,用字节流可以吗?计算机中的一切最终都是二进制的字节形式存在。对于“中国”这些字符,首先要得到其对应的字节,然后将字节写入到输出流。读取时,首先读到的是字节,可是我们要把它显示为字符,我们需要将字节转换成字符。由于这样的需求很广泛,人家专门提供了字符流的包装类。

底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转成字节再进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向IO设别写入或读取字符串提供了一点点方便。字符向字节转换时,要注意编码的问题,因为字符串转成字节数组,其实是转成该字符的某种编码的字节形式,读取也是反之的道理。讲解字节流与字符流关系的代码案例:

publicstaticvoidmain(String[]args)throwsException{Stringstr="中国人";/*FileOutputStreamfos=newFileOutputStream("1.txt");fos.write(str.getBytes("UTF-8"));fos.close();*//*FileWriterfw=newFileWriter("1.txt");fw.write(str);fw.close();*/PrintWriterpw=newPrintWriter("1.txt","utf-8");pw.write(str);pw.close();/*FileReaderfr=newFileReader("1.txt");char[]buf=newchar[1024];intlen=fr.read(buf);StringmyStr=newString(buf,0,len);System.out.println(myStr);*//*FileInputStreamfr=newFileInputStream("1.txt");byte[]buf=newbyte[1024];intlen=fr.read(buf);StringmyStr=newString(buf,0,len,"UTF-8");System.out.println(myStr);*/BufferedReaderbr=newBufferedReader(newInputStreamReader(newFileInputStream("1.txt"),"UTF-8"));StringmyStr=br.readLine();br.close();System.out.println(myStr);}11、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序:

1,张三,282,李四,353,张三,284,王五,355,张三,286,李四,357,赵六,288,田七,35

答案:

publicclassUser{privateStringname;privateinttimes;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetTimes(){returntimes;}publicvoidsetTimes(inttimes){this.times=times;}publicUser(Stringname,inttimes){super();this.name=name;this.times=times;}publicUser(){super();}@Overridepublicbooleanequals(Objectobj){Useru=(User)obj;returnthis.name.equals(u.name);}@OverridepublicStringtoString(){return"User[name="+name+",times="+times+"]";}publicstaticvoidmain(String[]args){Useruser1=newUser("lisi",8);Useruser2=newUser("zhangsan",18);System.out.println(user1.equals(user2));}}publicclassDemo01{publicstaticvoidmain(String[]args)throwsException{List<User>list=newArrayList<>();Filefile=newFile("data");FileReaderreader=newFileReader(file);BufferedReaderbr=newBufferedReader(reader);StringreadLine=null;while((readLine=br.readLine())!=null){intbeginIndex=readLine.indexOf(',');intendIndex=readLine.lastIndexOf(',');readLine=readLine.substring(beginIndex+1,endIndex);System.out.println(readLine);//将读取到的用户名构造出User对象Useruser=newUser();user.setName(readLine);user.setTimes(1);System.out.println(readLine);if(list.contains(user)){//若用户存在intindex=list.indexOf(user);Useruser2=list.get(index);user2.setTimes(user2.getTimes()+1);}else{//若用户不存在list.add(user);}}System.out.println(list.size());Collections.sort(list,newComparator<User>(){@Overridepublicintcompare(Usero1,Usero2){returno2.getTimes()-o1.getTimes();}});list.forEach(item->System.out.println(item));}}

程序代码如下(答题要博得用人单位的喜欢,包名用该公司,面试前就提前查好该公司的网址,如果查不到,现场问也是可以的。还要加上实现思路的注释):

publicclassGetNameTest{publicstaticvoidmain(String[]args){//InputStreamips=GetNameTest.class.getResourceAsStream("/com/huawei/interview/info.txt");//用上一行注释的代码和下一行的代码都可以,因为info.txt与GetNameTest类在同一包下面,所以,可以用下面的相对路径形式Mapresults=newHashMap();InputStreamips=GetNameTest.class.getResourceAsStream("info.txt");BufferedReaderin=newBufferedReader(newInputStreamReader(ips));Stringline=null;try{while((line=in.readLine())!=null){dealLine(line,results);}sortResults(results);}catch(IOExceptione){e.printStackTrace();}}staticclassUser{publicStringname;publicIntegervalue;publicUser(Stringname,Integervalue){this.name=name;this.value=value;}@Overridepublicbooleanequals(Objectobj){//下面的代码没有执行,说明往treeset中增加数据时,不会使用到equals方法。booleanresult=super.equals(obj);System.out.println(result);returnresult;}}privatestaticvoidsortResults(Mapresults){//TODOAuto-generatedmethodstubTreeSetsortedResults=newTreeSet(newComparator(){publicintcompare(Objecto1,Objecto2){//TODOAuto-generatedmethodstubUseruser1=(User)o1;Useruser2=(User)o2;/*如果compareTo返回结果0,则认为两个对象相等,新的对象不会增加到集合中去*所以,不能直接用下面的代码,否则,那些个数相同的其他姓名就打印不出来。**///returnuser1.value-user2.value;//returnuser1.value<user2.value?-1:user1.value==user2.value?0:1;if(user1.value<user2.value){return-1;}elseif(user1.value>user2.value){return1;}else{returnuser1.name.compareTo(user2.name);}}});Iteratoriterator=results.keySet().iterator();while(iterator.hasNext()){Stringname=(String)iterator.next();Integervalue=(Integer)results.get(name);if(value>1){sortedResults.add(newUser(name,value));}}printResults(sortedResults);}privatestaticvoidprintResults(TreeSetsortedResults){Iteratoriterator=sortedResults.iterator();while(iterator.hasNext()){Useruser=(User)iterator.next();System.out.println(user.name+":"+user.value);}}publicstaticvoiddealLine(Stringline,Mapmap){if(!"".equals(line.trim())){String[]results=line.split(",");if(results.length==3){Stringname=results[1];Integervalue=(Integer)map.get(name);if(value==null)value=0;map.put(name,value+1);}}}}

普通会员

1

帖子

60

回复

70

积分
沙发
发表于 2019-12-22 03:36:40

如果这就是爱,再转身的时候就该留下

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017