1-java刷题记录-1

1.synchronized关键字和volatile关键字比较:

在Java中,对基本数据类型的变量和赋值操作都是原子性操作
volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。
多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞
volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。
volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性。


2.通过HttpServletRequest. getParameter获取的参数.

编码格式由浏览器决定,浏览器根据html中指定的编码格式进行编码,tomcat根据指定的格式进行解码,另外get请求和post请求对编码格式的处理也是不同的


3.JVM堆内存中的区域

堆可以分为两部分:新生代,老年代。
新生代:1/3的堆空间 老年代:2/3的堆空间
而新生代可以细分:8/10的Eden区。2/10的Survivor区
Suivivor又可以细分为From区和To区,各占一半。
注意:
1.永久代MetaData在jdk1.8之前属于堆,现在属于物理内存,与堆完全隔开了
2.方法区只是逻辑概念,MetaData永久代和元空间是实实在在存在的,不能混为一体,元空间是方法区的具体实现。


4. 建立Statement对象的作用是

  1. Statement对象用于执行不带参数的简单SQL语句。
  2. Prepared Statement 对象用于执行预编译SQL语句。
  3. Callable Statement对象用于执行对存储过程的调用。
  4. JDBC的连接过程 1.加载驱动器 2.创建connection对象 3.创建statement–sql执行对象 4.编写sql语句 5.statement调用sql方法执行sql语句 6.创建处理结果集对象 7.处理结果,返回

5. java的关键字

true、false、null是常量
goto、const、是保留的关键字

abstract                continue           for            new        
switch                  default            if             package     
synchronized            do                 goto           private     
this                    break              double         implements   
protected               throw              byte           else       
import                  public             throws         case       
enum                    instanceof         return         transient  
catch                   extends            int            short       
try                     char               final          interface    
static                  void               class          finally   
long                    strictfp           volatile       const      
float                   native             super          while
boolean                 assert 

6. 子类A继承父类B, A a = new A(); 则父类B构造函数、父类B静态代码块、父类B非静态代码块、子类A构造函数、子类A静态代码块、子类A非静态代码块 执行的先后顺序是?

当实例化子类对象时,首先要加载父类的class文件进内存,静态代码块是随着类的创建而执行,所以父类静态代码块最先被执行,子类class文件再被加载,同理静态代码块被先执行;实例化子类对象要先调用父类的构造方法,而调用父类构造方法前会先执行父类的非静态代码块


7. java中提供了哪两种用于多态的机制

多态分为 编译时多态 和 运行时多态 。
其中 编辑时多态是静态的 , 主要是指方法的重载 ,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而 运行时多态是动态的 ,它是 通过动态绑定来实现的 ,也就是我们所说的多态性(要有继承关系 2.子类要重写父类的方法 3.父类引用指向子类)


8. 对象序列化

对象的序列化:Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
A、B:使用ObjectInputStream和ObjectoutputStream进行对象的传输
注意:1.基本数据类型的变量可以直接序列化
2.对象要被序列化,它的类必须实现Serializable接口,如果一个类中有引用类型的变量,这个引用类型的变量的类也必须实现Serializable接口。如果这个引用类型的变量不想被实例化,则用transient修饰(ObjectInputStream)


9. 运行时常量池

方法区是什么?
方法区是广义上的概念,是一个定义、标准,可以理解为Java中的接口,在Jdk6、7方法区的实现叫永久代;Jdk8之后方法区的实现叫元空间,并从JVM内存中移除,放到了直接内存中;
方法区是被所有方法线程共享的一块内存区域.

运行时常量池是什么?
运行时常量池是每一个类或接口的常量池的运行时表示形式.
具体体现就是在Java编译后生成的.class文件中,会有class常量池,也就是静态的运行时常量池;

运行时常量池存放的位置?
运行时常量池一直是方法区的一部分,在不同版本的JDK中,由于方法区位置的变化,运行时常量池所处的位置也不一样.JDK1.7及之前方法区位于永久代.由于一些原因在JDK1.8之后彻底祛除了永久代,用元空间代替。

运行时常量池存放什么?
存放编译期生成的各种字面量和符号引用;(字面量和符号引用不懂的同学请自行查阅)
运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。 此时不再是常量池中的符号地址了,这里换为真实地址。

运行时常量池与字符串常量池?(可能有同学把他俩搞混)
字符串常量池:在JVM中,为了减少相同的字符串的重复创建,为了达到节省内存的目的。会单独开辟一块内存,用于保存字符串常量,这个内存区域被叫做字符串常量池.

字符串常量池位置?
JDK1.6时字符串常量池,被存放在方法区中(永久代),而到了JDK1.7,因为永久代垃圾回收频率低;而字符串使用频率比较高,不能及时回收字符串,会导致导致永久代内存不足,就被移动到了堆内存中。

字面量和符号引用
字面量就是比如说int a = 1; 这个1就是字面量。又比如String a = “abc”,这个abc就是字面量。

在java中,一个java类将会编译成一个class文件。在编译时,java类并不知道引用类的实际内存地址,因此只能使用符号引用来代替。比如org.simple.People类要引用org.simple.Tool类,在编译时People类并不知道Tool类的实际内存地址,因此只能使用符号org.simple.Tool(假设)来表示Tool类的地址。而在类装载器装载People类时,此时可以通过虚拟机获取Tool类 的实际内存地址,因此便可以既将符号org.simple.Tool替换为Tool类的实际内存地址,及直接引用地址。

10. Thread.run()和Thread.start()的区别

  1. 函数不能以数字开头命名
  2. start()才是开启线程的方法
  3. 线程优先级高得先运行

11. final用法

public class Demo {
    public static String sRet = "";
    public static void func(int i)
    {
        try
        {
            if (i%2==0)
            {
                throw new Exception();
            }
        }
        catch (Exception e)
        {
            sRet += "0";
            return;
        } 
        finally
        {
            sRet += "1";
        }
        sRet += "2";
    }
    public static void main(String[] args)
    {
        func(1);
        func(2);
        System.out.println(sRet);
    }
}

第一步,func(1),if条件不成立,不抛出异常,catch不运行,final运行,拼串得到“1”,程序继续往下走,拼串得到“12”。
第二步,fun(2),if条件成立,抛出异常,catch捕获异常,运行catch里面代码,拼串得到“120”,虽然有return,但是不管出不出异常,final里代码必须执行,执行final,拼串得到“1201”,然后return结束。所以最终结果“1201”


12.对于非运行时异常,程序中一般可不做处理,由java虚拟机自动进行处理:错误

1.Java异常机制

Java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。Java中的异常分为两大类:错误Error和异常Exception,Java异常体系结构如下图所示:

2.Throwable

Throwable类是所有异常或错误的超类,它有两个子类:Error和Exception,分别表示错误和异常。其中异常Exception分为运行时异常(RuntimeException)和非运行时异常,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。

3.Error

一般是指java虚拟机相关的问题,如系统崩溃、虚拟机出错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误,因此应用程序不应该捕获Error对象,也无须在其throws子句中声明该方法抛出任何Error或其子类。

4.运行时异常和非运行时异常
(1)运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

当出现RuntimeException的时候,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。

出现运行时异常后,如果没有捕获处理这个异常(即没有catch),系统会把异常一直往上层抛,一直到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。

如果不想终止,则必须捕获所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。

(2)非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch并处理,否则程序就不能编译通过。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。

5. 常见RuntimeException:

ArrayStoreException: 试图将错误类型的对象存储到一个对象数组时抛出的异常

ClassCastException: 试图将对象强制转换为不是实例的子类时,抛出该异常

IllegalArgumentExceptio:抛出的异常表明向方法传递了一个不合法或不正确的参数

IndexOutOfBoundsException:指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出

NoSuchElementException:表明枚举中没有更多的元素

NullPointerException: 当应用程序试图在需要对象的地方使用 null 时,抛出该异常


13. 操作符

&按位与
|按位或
~按位取反
^按位异或
>>右移
>>>无符号右移
<<左移

14. 集合框架

1-java刷题记录-1_第1张图片


15. 数组命名规范

数组命名时名称与[]可以随意排列,但声明的二维数组中第一个中括号中必须要有值,它代表的是在该二维数组中有多少个一维数组


16. 继承

  1. 父类的引用直接指向子类的对象,即向上转型;当子类的引用直接指向父类的对象时,则需要强制转换。
  2. 单继承
  3. 抽象类和接口都可以继承或者实现抽象类和接口

17.java相关文件拓展名

.class 编译后的Java文件
.java是未编译的程序
.jsp是页面程序
.xml配置程序
.jar是.calss的集合

18. java数据类型

Java中,变量有两种类型,一种是原始类型,一种是引用类型。

原始类型一共有8种,它们分别是char,boolean,byte,short,int,long,float,double。在Java API中,
有它们对应的包装类,分别是(首字母大写)Character,Boolean,Byte,Short,Integer,Long,Float,Double(char,int的变化稍微大点)。

JAVA JVM对于不同的原始类型会分配不同的存储空间,具体分配如下:

byte  : 1个字节    8位
最大值: 127   (有符号)

short : 2个字节    1632767

int :     4个字节    322147483647

long:   8个字节    649223372036854775807

float:   4个字节    323.4028235E38

double:8个字节   641.7976931348623157E308

枚举(enum)类型是Java 5新增的特性,它是一种新的类型,允许用常量来表示特定的数
据片断,而且全部都以类型安全的形式来表示,是特殊的类,可以拥有成员变量和方法。

19. java concurrent包

1-java刷题记录-1_第2张图片


20. 接口

接口是对开闭原则的一种体现
接口中包含全局常量和抽象方法
接口中的变量默认是public static final 的
方法默认是public abstract

21.类之间存在以下几种常见的关系

IS-A 继承关系
HAS-A 聚合关系,比如B类中有A类型的成员
USES-A 依赖关系,比如B类中某个方法用到了A实例

22. java语言的下面几种数组复制方法

System.arraycopy()native方法+JVM手写函数,在JVM里预写好速度最快
clone()native方法,但并未手写,需要JNI转换,速度其次
Arrays.copyof():本质是调用1的方法
for():全是深复制,并且不是封装方法,最慢情有可原

23. 值传递和引用传递

  • call by value(值传递)
    值传递是将变量的一个副本传递到方法中,方法中如何操作该变量副本,都不会改变原变量的值。
  • call by reference(引用传递)
    引用传递是将变量的内存地址传递给方法,方法操作变量时会找到保存在该地址的变量,对其进行操作。会对原变量造成影响

24. 异常

= java.lang.NullPoninterException:变量未被初始化、对象未赋值、对象为空(俗称的空指针异常)

  • java.lang.NumberFormatException:数据格式转换失败(integer的取值范围为:-127-128,超过范围都会访问false)
  • java.lang.RuntimeException:运行时异常
  • java.lang.ArrayindexOutOfBoundsException:数组下标越界

25. try{}catch{}finally{}

  1. 不管有木有出现异常,finally块中代码都会执行;
  2. 当try和catch中有return时,finally仍然会执行;
  3. finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
  4. finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

26.继承

final不能被子类覆盖,但是基类的private方法,只有非private方法才能被覆盖。子类虽然继承了基类的所有内容,但是private和构造器等对子类是不可见的,不能直接访问,但是可以调用基类的非parivate方法从而访问基类的private方法,也会引起很多问题。


27. 集合框架

1-java刷题记录-1_第3张图片


28. Object类

1-java刷题记录-1_第4张图片


29. RMI相关

RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制。 而TCP/IP是远程通讯的主要手段。

30. 方法重载和方法重写

方法重载(overload):

  1. 必须是同一个类
  2. 方法名(也可以叫函数)一样
  3. 参数类型不一样或参数数量不一样

方法的重写(override)两同两小一大原则:

  1. 方法名相同,参数类型相同
  2. 子类返回类型小于等于父类方法返回类型,
  3. 子类抛出异常小于等于父类方法抛出异常,
  4. 子类访问权限大于等于父类方法访问权限。

31. Java内存区域

一、 程序计数器

一块较小的内存空间,可以看作是当前线程所执行的字节码的信号指示器。在虚拟机的概念模型里面,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要以来这个计数器完成。

由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正常的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java方法,计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法,计数器值应为空(Undefined)。

二、 Java虚拟机栈

与程序计数器一样,它也是线程私有的。

Java虚拟机栈描述的是Java方法执行的线程内存模型:
每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

什么是局部变量表:
存放了编译器可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,她并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。

这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long、double类型的数据会占用两个变量槽,其余的只占用一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

三、 Java堆

Java堆(Java Heap)虚拟机管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。

此内存的唯一目的就是:存放对象实例。

因此,Java堆也是垃圾收集器管理的内存区域。

四、 方法区

与Java堆一样,方法区是各个线程共享的内存区域,用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

1-java刷题记录-1_第5张图片

32. servlet的的生命路径

1-java刷题记录-1_第6张图片

33.HashMap和HashTable

  1. 继承的父类不同:HashTable继承Dictory类,HashMap继承AbstractMap.但都实现了Map接口;
  2. 线程安全性不同:HashTable是线程安全的,适用于多线程;HashMap是非线程安全,更适合于单线程;
  3. 是否提供contains方法:HashTable中保留了contains方法,与constainsValue功能相同;HashMap中去掉了contains方法;
  4. key和value是否可为null值:HashTable的key、value都不允许null值;HashMap,null可以作为key;
  5. 遍历方式的内部实现不同:HashTable、HashMap都使用了Iterator,HashTable还使用过Enumeration方式;
  6. hash值不同:HashTable直接使用对象的hashCode,而HashMap重新计算hash值。
  7. 内部使用的数组初始化和扩容方式不同:Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂;Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

34. String

  • length()方法是求String字符串对象中字符的个数
  • length是求字符串数组中有多少个元素。
  • str.split(’,’)是返回一个数组,即使找不到分隔符时,他仍然会返回一个数组

35. 多态

class Test {
    public static void main(String[] args) {
        System.out.println(new B().getValue());
    }
    static class A {
        protected int value;
        public A (int v) {
            setValue(v);
        }
        public void setValue(int value) {
            this.value= value;
        }
        public int getValue() {
            try {
                value ++;
                return value;
            } finally {
                this.setValue(value);
                System.out.println(value);
            }
        }
    }
    static class B extends A {
        public B () {
            super(5);
            setValue(getValue()- 3);
        }
        public void setValue(int value) {
            super.setValue(2 * value);
        }
    }
}

子类继承父类后,子类中的方法覆盖父类的方法以后,由于向上转型,父类调用方法的时候是调用子类的,除非用super。
还有一个点就是在Try catch finally 体系当中,在return之前始终会执行finally里面的代码,如果finally里面有return,则数据跟随finally改变。如果没有return,则原数据不跟随finally里改变的数据改变!

36. 字节输入流

  • java.io.InputStream : 此抽象类是表示字节输入流的所有类的超类
  • java.io.OutputStream : 此抽象类是表示字节输出流的所有类的超类

37. java包

图形用户界面(Graphical User Interface,简称 GUI)是指采用图形方式显示的计算机操作用户界面。

  • java.io提供了全面的IO接口。包括:文件读写、标准设备输出等。
  • java.sql 提供使用 Java 编程语言访问并处理存储在数据源中的数据的 API。此 API 包括一个框架,凭借此框架可以动态地安装不同驱动程序来访问不同数据源。
  • java.awt是一个软件包,包含用于创建用户界面和绘制图形图像的所有分类。功能:包含用于创建用户界面和绘制图形图像的所有类。
  • java.rmi 提供 RMI 包。RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。

38. 抽象类

包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

2)抽象类不能用来创建对象;

3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

在其他方面,抽象类和普通的类并没有区别。

39. 锁

  • 共享锁(读锁)
    如果事务对数据A添加共享锁后,其他事务只能对A添加共享锁不可以添加排它锁,他可以被多线程共同读取,但无法区修改添加删除数据,只可以被读。

  • 排它锁(写锁)
    排他锁又叫做写锁,独占锁,当事务T对数据A添加排它锁后,该事物只允许读取A和修改,其他的事务都不可以在对数据A添加锁,直到事务提交完成后。他可以保证其他事务不能读取该数据和写数据。

  • 互斥锁
    其实概念和排他锁差不多,这里可以参考互斥锁和读写锁的区别,互斥锁只允许一个线程访问近来,过程中其他线程必须等待。

  • 悲观锁
    悲观锁顾名思义,就是很悲观,当我们要操作数据的时候,会很悲观的想象可能会有其他线程会修改当前数据,所以每次操作前都会加锁,synchronized就是悲观锁。

  • 乐观锁
    就是很乐观,每次拿数据的时候认为其他人不会修改,所以不会上锁,但是拿的时候会判断其他线程是否更新过这个数据,可以使用原子引用,版本号去进行控制。乐观锁适用于读多写少的场景。这种锁可以提高吞吐量因为这样就不用线程排队了。数据库中write——condition就是这种机制还有cas。

  • 行级锁
    他通常是用于mysql数据库中,锁表中的某一行,他的开销非常大,他会减少数据库的操作冲突。加锁粒度最小。开销大加锁慢,会出现死锁

  • 表级锁
    表级锁是锁定粒度最大的锁,对整张表加锁它实现简单,资源消耗最少,被大部分mysql引擎支持。mylsam和innodb都支持表锁。表级锁分为共享锁和排他锁。发生锁冲突概率最高。

  • 页级锁
    页级锁是所粒度基于行和表中间的锁。

  • 分段锁
    ConcurrentHashMap使用了分段锁来保证线程安全,效率比起使用synchronized的HashTable要高的很多。每个集合都可以看作是一个存储东西的房子,HashTable与ConcurrentHashMap存储的都是HashEntry数组(每个数组里面是链表,暂且忽略,直到就好)。

    • HashTable:

    在HashTable这个房子中,只有一个房间,就像是一个大仓库,里面是一大长列的存放Entry的货架(数组);只要有一个人进了这个房间,他就会把这个房间锁起来,直到这个人在房间里面做完了事情出来之后才会把门打开。此间如果有其他人想要进去,就只能在外面等这个人把房门打开,然后才能进去。这样的话会导致外面等了很多人,效率不高。

    • ConcurrentHashMap:

    在ConcurrentHashMap这个房子中,有许多的房间,每个房间都存着一部分的Entry货架(Entry数组的不同段,将一整个的Entry数组分开了),而这些房间各自又有着不同的锁。一个人在访问某一个房间的时候,会把这个房间锁起来,其他的房间依然是可以进去访问的,这样就大大的提高了效率。

    在HashTable中,如果线程A想要访问Entry数组前面位置的元素,线程B想要访问数组尾部的位置的元素,但是A先进房间访问了,那么房子就被锁了,B不得不等待。在ConcurrentHashMap中,A进到了前面位置元素所在的房间访问,B仍然可以去尾部元素所在的房间,因为他们处在不同的房间。

    分段锁在我的理解中是先分段再锁,将原本的一整个的Entry数组分成了若干段,分别将这若干段放在了不同的新的Segment数组中(分房间),每个Segment有各自的锁,以此提高效率。

40. 事务中包含的问题

  • 脏读
    脏读就是读到了无用的数据,意思就是读到了事务还没有提交的数据。
    脏读又称无效数据读出(读出了脏数据)。一个事务读取另外一个事务还没有提交的数据叫脏读。

例如:事务T1修改了某个表中的一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因回滚(Rollback)了,那么事务T2读取的数据就是脏的(无效的)。

解决办法:把数据库的事务隔离级别调整到READ_COMMITTED(读提交/不可重复读)

  • 不可重复读
    在事务中,两次查询相同的数据,返回的不同的结果,造成的原因是另一个事务修改了该数据,
    解决办法:把数据库的事务隔离级别调整到REPEATABLE_READ(可重复读)

  • 幻读
    当一个事务删除所有数据后,另一个事务恰好又添加一条数据,第一个事务就会产生自己搞错了,还没有删干净的错觉。
    解决办法:把数据库的事务隔离级别调整到SERIALIZABLE_READ(序列化执行),或者数据库使用者自己进行加锁来保证。
    数据库默认隔离级别为repeatable-read。

  • 小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

  • 读未提交:意思就是其他事务更改数据后,本事务也可以读到,容易造成脏读。

  • 读已提交:只能读到已提交的数据。

41. 要使某个类能被同一个包中的其他类访问,但不能被这个包以外的类访问,可以用default

包以外的类包括子类
外部包 > 子类 > 本包 > 该类内部
publi c> protected > default > private

42. 需要所有线程都执行到某一处,才进行后面的的代码执行我们可以使用

  • CountDownLatch 是等待一组线程执行完,才执行后面的代码。此时这组线程已经执行完。
  • CyclicBarrier 是等待一组线程至某个状态后再同时全部继续执行线程。此时这组线程还未执行完。
  • CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置。
  • Semaphore 通常我们叫它信号量, 可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。
  • future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作

43. 编译错误和运行报错

编译错误:写代码的时候就报错
运行报错:运行的时候才报错

44. 抽象方法和最终方法

  • 抽象类
    1,抽象类中可以有抽象方法,也可以没有抽象方法。
    2,抽象类当然可以被继承,因为它就是用来继承的,
    3,继承抽象类,若有抽象方法,则子类必须将其抽象方法实现,
    4,抽象类中的非抽象方法可以被重写。

  • 最终类
    5,加上final的类就叫最终类,加上final的方法就叫最终方法,
    6,最终类中可以有最终方法也可以没有
    7,最终类不能有子类,最终方法不能被重写

45. java语言标识符

  • 标识符的组成元素是字母(a-z,A-Z),数字(0~9),下划线(_)和美元符号($)。
  • 标识符不能以数字开头。
  • java的标识符是严格区分大小写的。
  • 标识符的长度可以是任意的。
  • 关键字以及null、true、false不能用于自定义的标识符。

46. 类加载机制

47. try{}catch{}finally{}

如果try语句里有return,那么代码的行为如下:

  1. 如果有返回值,就把返回值保存到局部变量中
  2. 执行jsr指令跳到finally语句里执行
  3. 执行完finally语句后,返回之前保存在局部变量表里的值
    如果try,finally语句里均有return,忽略try的return,而使用finally的return.

48. String s=“welcome”+“to”+360;只创建了一个对象

“welcome”,“to”,360都是字面量,会在编译的时候放在常量池里面,拼接成"welcometo360"后才会创建一个对象来存放这个字符串

49. equals()和==的区别

==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同
equals()是先比引用,引用一样再比的是实际的值

50. toLowerCase()的底层实现

ue、false不能用于自定义的标识符。

46. 类加载机制

[外链图片转存中…(img-FGRYnNog-1648095821477)]

47. try{}catch{}finally{}

如果try语句里有return,那么代码的行为如下:

  1. 如果有返回值,就把返回值保存到局部变量中
  2. 执行jsr指令跳到finally语句里执行
  3. 执行完finally语句后,返回之前保存在局部变量表里的值
    如果try,finally语句里均有return,忽略try的return,而使用finally的return.

48. String s=“welcome”+“to”+360;只创建了一个对象

“welcome”,“to”,360都是字面量,会在编译的时候放在常量池里面,拼接成"welcometo360"后才会创建一个对象来存放这个字符串

49. equals()和==的区别

==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同
equals()是先比引用,引用一样再比的是实际的值

50. toLowerCase()的底层实现

toLowerCase()的返回值实际上是new了一个小写字母字符串,然后返回,和原来的字符串引用时不一样的

你可能感兴趣的:(java)