0%

Java疑难知识点

1.问题: 增强for循环赋值并且向list集合里添加元素,每个元素都一样?

可能原因:构造器写在了外面,每次add()添加的都是同一个元素,更改器方法改变的也是同一个元素的值,list集合最后每个元素都是最后一次赋值生成的值

解决方法:把构造器写在增强for循环里面。

2.list remove方式

  1. for循环遍历删除,要注意索引左移问题(可以通过同步索引递减或者倒序来实现)

  2. List删除元素时,为避免陷阱,建议使用迭代器iterator的remove方式。

  3. Foreach不可以用来删除

  4. List删除元素时,默认按索引删除,而不是对象删除。

    参考文档:[https://blog.csdn.net/pelifymeng2/article/details/78085836](https://blog.csdn.net/pelifymeng2/article/details/78085836)
  5. java.util.NoSuchElementException 报错原因分析

    3.1 错误原因:循环中误用两次next()

    while(iter.hasNext()) {
    x.put(iter.next().getxx(),iter.next().getxx());

       }
    解决方法:
    while(iter.hasNext()) {
           String xxx = iter.next();
           x.put(xxx.getxx(),xxx.getxx());
       }

    3.2 错误原因:在进行输入输出的时候,提前关闭流。

    解决方法:在所有迭代结束后关闭。

    3.3 错误原因:迭代移除后未跳出。

    解决方法:移除的方法后加break跳出。

4.对象向上或向下转型

向上转型:

注意点:父类指向子类引用对象会遗失除与父类对象共有的其他方法,也就是在转型过程中,子类的新有的方法都会遗失掉,在编译时,系统会提供找不到方法的错误。

优点:以父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。

向下转型:

注意点:

情况一:如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的。也就是编译是不会出错误的。

  情况二:如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误。

总结:

  1. 父类引用可以指向子类对象,子类引用不能指向父类对象。
  2. 向上不用强制,向下需要强制。
  3. 向上会丢失子类特有的方法,但是子类overriding 父类的方法,子类方法有效。
  4. Instanceof:java中,instanceof运算符的前一个操作符是一个引用变量,后一个操作数通常是一个类(可以是接口),用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是返回true,否则返回false。

6.List判空(null表示list没有,size长度为零表示list内元素为空)

错误方式:

if (list.size() != 0) {}

正确方式:

if (list != null && list.size() != 0)或者
if(list != null && !list.isEmpty()) {}

两者含义:

 list == null :用于判断list有没有初始化,也就是list是否被赋为null,如 List list = null; ,满足该条件的话list中是没有数据的

 list.size == 0 :用于判断list中是否有数据,满足该条件时list中也是没有数据的

 总结:如果只使用 list == null :一旦list进行了初始化 List list2 = new ArrayList(); ,此时list就不再为null了,但list内并没有数据。如果只使用 list     ==   null 来判断是否为空的话,就会判断错误。

如果只使用 list .size == 0 :如果list并没有进行初始化,使用该条件时会报空指针错误,就无法达到判空的目的。因此在使用该条件时,一定要判断list是否进行了初始化。

  1. VO DTO DO PO

    简单概念:

  2. VO:视图对象,用于展示层封装指定页面数据。

  3. DTO:数据传输对象,展示层与服务层之间的数据传输对象。

  4. DO:领域对象,抽象的业务实体。

  5. PO:持久化对象,数据库映射对象。

简单模型:

l 用户发出请求(可能是填写表单),表单的数据在展示层被匹配为VO。

l 展示层把VO转换为服务层对应方法所要求的DTO,传送给服务层。

l 服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。

l 服务层把DO转换为持久层对应的PO(可以使用ORM工具,也可以不用),调用持久层的持久化 方法,把PO传递给它,完成持久化操作。

参考资料:[https://www.cnblogs.com/qixuejia/p/4390086.html](https://www.cnblogs.com/qixuejia/p/4390086.html)

8.进程和线程

进程有自己独立的内存空间,线程是其的一个执行流程。线程之间共享进程分配的虚拟地址空间与资源。

在Java中,每次程序运行至少启动2个线程:一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM实际上就是在操作系统中启动了一个进程。

线程总体分两类:用户线程和守候线程。

9.进程和线程相关问题

9.1 锁和同步

  1. 只能同步方法而不能同步变量和类;

  2. 每个对象只有一个锁,注意锁的位置;

  3. 不必同步类中的所有方法,类可以同时拥有同步和非同步的方法。

  4. 线程睡眠时,它所持的任何锁都不会释放。

  5. synchronized只能标记非抽象的方法,不能标识成员变量。

  6. 线程睡眠时,它所持的任何锁都不会释放。

  7. 线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。

  8. 同步损害并发性,应该尽可能缩小同步范围。

只要调用notify()并不意味着这是该锁可用,因为如果线程任然在完成同步代码,则在线程在移除之前不会放弃锁的。

注意点: 在使用synchronized关键字时候,应该尽可能避免在synchronized方法或synchronized块中使用sleep或者yield方法,因为synchronized程序块占有着对象锁,你休息那么其他的线程只能一边等着你醒来执行完了才能执行。不但严重影响效率,也不合逻辑。

      同样,在同步程序块内调用yeild方法让出CPU资源也没有意义,因为你占用着锁,其他互斥线程还是无法访问同步程序块。当然与同步程序块无关的线程可以获得更多的执行时间。

10.线程的优先级和让步

yield()方法的作用

  1. 暂停当前正在执行的线程对象,并执行其他线程。

  2. 在大多数情况下,当前运行的线程优先级大于或等于线程池中任何线程的优先级。

  3. 优先级相同时候,jvm任选一个或者利用时间分片提供均等运行机会。

    调用join()方法

    保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。

    优先级高只是获取CPU资源的概率变大,并不代表优先级低的没机会执行。

11.Callable接口

关于为什么一定要用FutureTask去接受返回值?

Callable接口中只有一个call()方法,和Runnable相比,该方法有返回值并允许抛出异常。

但是这里有一个问题,进程是要通过Thread类去创建的,但是Thread的target必须是实现了Runnable接口的类对象,所以Callable对象无法直接作为Thread对象的接口;所以要想作为target,必须同时实现Runnable接口。

Java提供了一个FutureTask类,该类实现了Runnable接口,该类的run()方法会调用Callable对象的call()方法,这样就能把Callable和Thread结合起来使用了。同时为了方便对Callable对象的操作,Java还提供了Future接口。

 参考文档:[https://www.cnblogs.com/cuimiemie/p/6445154.html](https://www.cnblogs.com/cuimiemie/p/6445154.html)

                   [https://blog.csdn.net/binggetong/article/details/81604283](https://blog.csdn.net/binggetong/article/details/81604283)

11.jvm内存分为私有领域(程序计数器,虚拟机栈,本地方法区)、线程共享域(java堆,方法区)、直接内存。

线程私有数据区域生命周期与线程相同,依赖用户线程的启动/结束 而 创建/销毁。

线程共享区域随虚拟机的启动/关闭而创建/销毁。

  1. Throw和Throws区别

  2. Java内部类

    静态内部类:

    成员内部类:

    定义在类内部的非静态类,就是成员内部类。成员内部类不能定义静态方法和变量(final 修饰的除外)。这是因为成员内部类是非静态的,类初始化的时候先初始化静态成员,如果允许成员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的。

    局部内部类(定义在方法中的类):

    只在某个方法中使用

匿名内部类(要继承一个父类或者实现一个接口、直接使用new 来生成一个对象的引用)

-------------本文结束元宝感谢您的阅读-------------