java错题

枚举(enum)属于基本数据类型(primitive type)(错误)错题

java有八大基础数据类型包括byte(1字节),short(2字节),int(4字节),long(8字节),float(4字节),double(8字节),char(2字节),boolean(1字节)

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

java中的各种修饰符作用范围 错题

访问修饰符

private

被private修饰的属性和方法,不能被其他类访问,子类不能继承也不能访问。只能在所在类内部访问。

缺省

变量或者方法前没有访问修饰符时,可以被所在类访问,可以被同一包内的其他类访问 或者继承。但是不能被其他包访问。

protected

被protected修饰的方法和属性,在同一包内可被访问和继承。不同包内,子类可继承,非子类不能访问。

public

方法和属性前有public修饰,可以被任意包内的类访问。

另外,类要想被其他包导入,必须声明为public。被public修饰的类,类名必须与文件名相同。

静态修饰符

知识点

abstract类和final类

错题

内部类总结 错题

方法的重载

有些类有多个构造器。例如, 可以如下构造一个空的 StringBuilder 对象:

StringBuilder messages = new StringBuilderO ;

或者, 可以指定一个初始字符串:

StringBuilder todoList = new StringBuilderC'To do:\n";)

这种特征叫做重载( overloading。) 如果多个方法(比如, StringBuilder 构造器方法)有

相同的名字、 不同的参数,便产生了重载。编译器必须挑选出具体执行哪个方法,它通过用

各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出相应的方法。如

果编译器找不到匹配的参数, 就会产生编译时错误,因为根本不存在匹配, 或者没有一个比

其他的更好。(这个过程被称为重载解析(overloading resolution)

。)

Java 允许重载任何方法, 而不只是构造器方法。因此,要完整地描述一个方法, 需要指出方法名以及参数类型。这叫做方法的签名(signature) 。例如, String 类有 4 个 称为 indexOf 的公有方法。它们的签名是 indexOf(int) indexOf(int, int) indexOf(String) indexOf(String, int) 返回类型不是方法签名的一部分。也就是说, 不能有两个名字相同、 参数类型也相 同却返回不同类型值的方法。

总结重载;
方法名称必须相同
参数列表必须不同(个数不同、或类型不同、参数类型排列顺序不同等)
对返回值没有要求

字符串修改 链接

字符串对象是不可变的是指字符串常量在字符串池中的值不会被改变,比如

String a="kevin";
a="jack";
String c="jack";
String d=new String("jack");
/*
修改a就是让a指向了jack在内存中的地址,原来的地址会被gc回收
a和c都指向了jack,他们存储的是同一个jack的地址,因为java会从字符串池里寻找如果值相同就指向同一个
d虽然也指向jack但是new String()方法的是开辟了一个新的空间去存储jack,所以d和ac是不一样的地址
*/

学习链接YouTube

线程错题

volatile与synchronized的区别:

volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.

volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.

volatile仅能实现变量的修改可见性,但不具备原子特性,而synchronized则可以保证变量的修改可见性和原子性.

volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.

volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化.

ArrayLists和LinkedList的区别,下述说法正确的有链接

自增和自减 链接

 public void test() {
        int a = 10;
        System.out.println(a++ + a--);
    }

将a++和a--看成两个变量x和y,a++是先赋值再自加所以x是10,a--也是先赋值再自减,注意的是这里a--是在a++完之后的操作了所以现在a是在11的基础上自减的所以y是11,x+y=21

jvm参数求eden区最终分配的大小是多少 链接

Xms 起始内存

Xmx 最大内存

Xmn 新生代内存

Xss 栈大小。 就是创建线程后,分配给每一个线程的内存大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

关于以下代码的说明,正确的是( )

链接

java初始化的加载顺序为:

父类静态成员变量 父类静态代码块 子类静态成员变量 子类静态代码块 父类非静态成员变量,父类非静态代码块,父类构造函数,子类非静态成员变量,子类非静态代码块,子类构造函数

在Java线程状态转换时,下列转换不可能发生的有 错题

final、finally和finalize的区别中,下述说法正确的有?错题

++错题 链接

count++有返回值,返回值是自加前的值,count=count++无论循环几次结果不变,如果是想实现自加的话应该改为count++就好了

5. 下列流当中,属于处理流的是:() 

2. 下列哪种异常是检查型异常,需要在编写程序时声明?

4. 在java7中,下列不能做switch()的参数类型是?

switch支持byte、short、char、int、String(jdk1.7)、Enum

Java1.8版本之前的前提,Java特性中,abstract class和interface有什么区别()

在JDK1.8之前的版本(不包括JDK1.8),接口中不能有静态方法,抽象类中因为有普通方法,故也可以有静态方法。

在JDK1.8后(包括JDK1.8),在抽象类中依旧可以有静态方法,同时在接口中也可以定义静态方法了。

以下代码在JDK1.8之后是没有问题的(可以通过接口名来调用静态方法 :Main.prinf(); ):

public interface Demo{     
    public static void print() {               
    System.out.println("Hello World!");    
    } } 

PS:

在JDK1.7,接口中只包含抽象方法,使用public abstract 修饰。

public interface Demo{
    public abstract void method();
}

在JDK1.8,接口中新加了默认方法和静态方法:

默认方法:使用default修饰,在接口的实现类中,可以直接调用该方法,也可以重写该方法。

静态方法:使用static修饰,通过接口直接调用。

public interface Demo{     
    //默认方法    
    public default void method(){        
        System.out.println("default method...");   
    }    
    //静态方法     
    public static void print(){        
    System.out.println("static method...");   
    } }

在JDK1.9,接口中新加了私有方法,使用private修饰,私有方法供接口内的默认方法调用。

public interface Demo{    
    private void method() {       
        System.out.println("Hello World!");  
    } } 

下面哪个修饰符修饰的变量是所有同一个类生成的对象共享的

public class foo {
    public static void main(String sgf[]) {
 
        StringBuffer a=new StringBuffer("A");
 
        StringBuffer b=new StringBuffer("B");
 
        operate(a,b);
 
        System.out.println(a+"."+b);
    }
    static void operate(StringBuffer x,StringBuffer y) {
        x.append(y);
        y=x;
    }
}

java中都是值传递,而对引用类型传递的是引用的值,所以a,x都指向A,而b和y都指向B,然后执行x.append(y)是在引用的值修改,所以a和x都指向了新的值AB,而y=x则是改变y的引用地址,指向AB,对于b是没有变化的

ServletConfig接口默认是哪里实现的?

关于访问权限说法正确 的是 ? ( )

// public 
class ClassD {// ClassD 为外部类,可以没有 public , 且只能带上 public, 不可以使用 protected,private 等其他

    // public, protected
    private static final class E {// E 为成员内部类, 可以加上 public,protected,private, 等和 static final

    }

    public static void main(String[] args) {

        class G {// 局部内部类

        }

    }

    public void test() {
        final class H {// 局部内部类 , 不可以加上 static 和 public,protected,private 等, 可以带上 final

        }
    }

}

下面代码输出结果是?

class C {
    C() {
        System.out.print("C");
    }
}

class A {
    C c = new C();

    A() {
        this("A");
        System.out.print("A");
    }

    A(String s) {
        System.out.print(s);
    }
}

class Test extends A {
    Test() {
        super("B");
        System.out.print("B");
    }

    public static void main(String[] args) {

        new Test();
    }
}

类的加载顺序:

父类静态成员变量、静态块>子类静态成员变量、静态块>父类普通成员变量、非静态块>父类构造函数>子类普通成员变量、非静态块>子类构造函数

这题最大的坑在于,会不会调用父类(A)的无参构造。

因为Test已经显式调用了super("B"),所以会直接调用A的有参构造。

如果删除super("B"),系统才会默认调用父类无参构造,此时答案为:CAAB。

如果子类的构造器没有显式地调用超类的构造器, 则将自动地调用超类默认(没有参数 ) 的构造器。 如果超类没有不带参数的构造器, 并且在子类的构造器中又没有显式地调用超类 的其他构造器’ 则 Java 编译器将报告错误。

关键字 this 有两个用途: 一是引用隐式参数,二是调用该类其他的构 造器 , 同样,super 关键字也有两个用途:一是调用超类的方法,二是调用超类的构造器。 在调用构造器的时候,这两个关键字的使用方式很相似。调用构造器的语句只能作为另 一个构造器的第一条语句出现。构造参数既可以传递给本类( this) 的其他构造器,也可 以传递给超类(super ) 的构造器。

off-heap是指那种内存()

off-heap叫做堆外内存,将你的对象从堆中脱离出来序列化,然后存储在一大块内存中,这就像它存储到磁盘上一样,但它仍然在RAM中。对象在这种状态下不能直接使用,它们必须首先反序列化,也不受垃圾收集。序列化和反序列化将会影响部分性能(所以可以考虑使用FST-serialization)使用堆外内存能够降低GC导致的暂停。堆外内存不受垃圾收集器管理,也不属于老年代,新生代。

JDK1.8版本之前,抽象类和接口的区别,以下说法错误的是

在类之间, 最常见的关系有 •依赖(“ uses-a ”) •聚合(“ has-a ”) •继承(“ is-a ”) ,组合关系("like-a")

依赖( dependence ), 即“ uses-a ” 关系, 是一种最明显的、 最常见的关系。例如,Order 类使用 Account 类是因为 Order 对象需要访问 Account 对象查看信用状态。但是 Item 类不依 赖于 Account 类, 这是因为 Item 对象与客户账户无关。因此, 如果一个类的方法操纵另一个 类的对象,我们就说一个类依赖于另一个类。

应该尽可能地将相互依赖的类减至最少。如果类 A 不知道 B 的存在, 它就不会关心 B 的任何改变(这意味着 B 的改变不会导致 A 产生任何 bug ) 。用软件工程的术语来说,就是 让类之间的耦合度最小。

聚合(aggregation ), 即“ has-a ” 关系, 是一种具体且易于理解的关系。例如, 一个 Order 对象包含一些 Item 对象。聚合关系意味着类 A 的对象包含类 B 的对象

继承( inheritance ), 即“ is-a ” 关系, 是一种用于表示特殊与一般关系的。例如,Rush Ordei•类由 Order 类继承而来。在具有特殊性的 RushOrder 类中包含了一些用于优先处理的 第 4 章?象与? 9 5 特殊方法, 以及一个计算运费的不同方法;而其他的方法, 如添加商品、 生成账单等都是从 Order 类继承来的。一般而言, 如果类 A 扩展类 B, 类 A 不但包含从类 B 继承的方法,还会 拥有一些额外的功能(下一章将详细讨论继承,其中会用较多的篇幅讲述这个重要的概念。

1.is-a关系:表示子类和父类之间的继承关系。比如:一个Student类,继承了父类Person类,我们可

以说一个学生就是一个人,也就是Student is a Person。

2.has-a关系:表示的是从属关系。比如:一个类有多个对象(人有多种职业,学生是其中的一

种),一个对象有多种属性(学生有班级,学号,成绩等等属性),这些就是从属关系。

3.like-a关系:表示的是接口的实现类和接口之间的关系。比如:我们都说UZI是一个神一样的男

人,简单来说就是UZI like a 神,这里“UZI”就是接口的实现类,“神”就是接口(因为接口可以理解

为就是一种抽象类),我们可以推出like-a关系,就是具体和抽象之间的关系。

4.use-a关系:表示的是一个类和另外一个类的属性或方法之间的关系。比如:一个类里面new了

另外一个类的对象,我们就可以使用这个对象调用另一个类的方法或属性,这就是use-a关系。通

俗的理解就是:你手机没电了,又没带充电宝,所以你就借用了你兄弟的充电宝。你用的不是自己

的,是别人的。

很多程序员采用 UML ( Unified Modeling Language , 统一建模语言)绘制类图,用来描 述类之间的关系。图 4-2 就是这样一个例子。类用矩形表示,类之间的关系用带有各种修饰 的箭头表示。表 4-1 给出了 UML 中最常见的箭头样式

1)接口可以继承接口,而且可以继承多个接口,但是不能实现接口,因为接口中的方法全部是抽象的,无法实现;

另外,如果是Java 7以及以前的版本,那么接口中可以包含的内容有:1. 常量;2. 抽象方法
如果是Java 8,还可以额外包含有:3. 默认方法;4. 静态方法
如果是Java 9,还可以额外包含有:5. 私有方法
 

2)普通类可以实现接口,并且可以实现多个接口,但是只能继承一个类,这个类可以是抽象类也可以是普通类,如果继承抽象类,必须实现抽象类中的所有抽象方法,否则这个普通类必须设置为抽象类;

3)抽象类可以实现接口,可以继承具体类,可以继承抽象类,也可以继承有构造器的实体类。

抽象类中可以有静态main方法;抽象类里可以没有抽象方法,没有抽象方法的抽象类就是不想让别人实例化它;

另外,抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super(参数列表)调用抽象类中的构造方法,可以用于实例化抽象类的字段。

下面总结常见的抽象类与接口的区别:

1)抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象;

2)接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现(java8中 接口可以有实现方法 使用default修饰);

3)接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量;

4)抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类;

5)抽象方法要被实现,所以不能是静态static的,也不能是私有private的,也不能被final修饰(试想一下,静态方法可以被类名直接调用,而类名直接调用一个没有实现的抽象方法没有意义)。

一般情况下,以下哪个选项不是关系数据模型与对象模型之间匹配关系?

  • 表对应类
  • 记录对应对象
  • 表的字段对应类的属性

表之间的参考关系与类之间的依赖关系没有直接联系

下列代码执行结果为()

public static void main(String args[])throws InterruptedException{
            Thread t=new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.print("2");
                }
            });
            t.start();
             
            t.join();
            System.out.print("1");
        }

join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。

下面哪项技术可以用在WEB开发中实现会话跟踪实现?

会话跟踪是一种灵活、轻便的机制,它使Web上的状态编程变为可能。 HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。当一个客户在多个页面间切换时,服务器会保存该用户的信息。 有四种方法可以实现会话跟踪技术:URL重写、隐藏表单域、Cookie、Session。

1)隐藏表单域:<input type="hidden">,非常适合步需要大量数据存储的会话应用。

2)URL 重写:URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。

3)Cookie:一个 Cookie 是一个小的,已命名数据元素。服务器使用 SET-Cookie 头标将它作为 HTTP 响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个 Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至 在客户端计算机重启后它仍可以保留其值

4)Session:使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话

TestSuper和Date的getClass都没有重写,他们都是调用Object的getClass,而Object的getClass作用是返回的是运行时的类的名字。这个运行时的类就是当前类,所以 super.getClass().getName() 返回的是test.SuperTest,与Date类无关 要返回Date类的名字需要写super.getClass().getSuperclass()

TestSuper和Date的getClass都没有重写,他们都是调用Object的getClass,而Object的getClass作用是返回的是运行时的类的名字。这个运行时的类就是当前类,所以 super.getClass().getName() 返回的是test.SuperTest,与Date类无关 要返回Date类的名字需要写super.getClass().getSuperclass()

对于文件的描述正确的是( )

A.文件分为文本文件和二进制文件,计算机只认识二进制,所以实际上都是二进制的不同解释方式。文本文件是以不同编码格式显示的字符,例如Ascii、Unicode等,window中文本文件的后缀名有".txt",".log",各种编程语言的源码文件等;二进制文件就是用文本文档打开是看不懂乱码,只要能用文本打开的文件都可以算是文本文件,只是显示的结果不是你想要的,二进制文件只有用特殊的应用才能读懂的文件,例如".png",".bmp"等,计算机中大部分的文件还是二进制文件。

B.File类是对文件整体或者文件属性操作的类,例如创建文件、删除文件、查看文件是否存在等功能,不能操作文件内容;文件内容是用IO流操作的。

C.当输入过程中意外到达文件或流的末尾时,抛出EOFException异常,正常情况下读取到文件末尾时,返回一个特殊值表示文件读取完成,例如read()返回-1表示文件读取完成。

D.上面A选项已经说了,不论是文本文件还是二进制文件,在计算机中都是以二进制形式存储的,所以都当做二进制文件读取。

以下哪一个正则表达式不能与字符串“https://www.tensorflow.org/”(不含引号)匹配?()

正则表达式的规则

 1. 任意一个字符表示匹配任意对应的字符,如a匹配a,7匹配7,-匹配-。    


 2. []代表匹配中括号中其中任一个字符,如[abc]匹配a或b或c。    


 3. -在中括号里面和外面代表含义不同,如在外时,就匹配-,如果在中括号内[a-b]表示匹配26个小写字母中的任一个;[a-zA-Z]匹配大小写共52个字母中任一个;[0-9]匹配十个数字中任一个。    


 4. ^在中括号里面和外面含义不同,如在外时,就表示开头,如^7[0-9]表示匹配开头是7的,且第二位是任一数字的字符串;如果在中括号里面,表示除了这个字符之外的任意字符(包括数字,特殊字符),如[^abc]表示匹配出去abc之外的其他任一字符。    


 5. .表示匹配任意的字符。    


 6. \d表示数字。    


 7. \D表示非数字。    


 8. \s表示由空字符组成,[ \t\n\r\x\f]。    


 9. \S表示由非空字符组成,[^\s]。    


 10. \w表示字母、数字、下划线,[a-zA-Z0-9_]。    


 11. \W表示不是由字母、数字、下划线组成。    


 12. ?: 表示出现0次或1次。    


 13. +表示出现1次或多次。    


 14. *表示出现0次、1次或多次。    


 15. {n}表示出现n次。    


 16. {n,m}表示出现n~m次。    


 17. {n,}表示出现n次或n次以上。    


 18. XY表示X后面跟着Y,这里X和Y分别是正则表达式的一部分。    


 19. X|Y表示X或Y,比如"food|f"匹配的是foo(d或f),而"(food)|f"匹配的是food或f。    


 20. (X)子表达式,将X看做是一个整体

二、Java中如何写正则表达式
在java中调用正则表达式的类是java.util.regex.Matcher和java.util.regex.Pattern,java.util.regex包是从jdk1.4开始提供的。有多种写法来使用正则表达式。

  1. 仅仅是匹配

1). 实现方式1,匹配一个数字。

public void regex1() {

        //要匹配的字符

        String str = "8";

        //正则表达式

        String regex = "[0-9]";

        //返回匹配的结果,匹配成功就返回true,失败就返回false,此次匹配返回true。

        boolean flag = Pattern.matches(regex, str);

        System.out.println(flag);

}

2). 实现方式2, 匹配3个到5个字母,大小写不限,包括3和5个。

public void regex2() {

    //要匹配的字符

    String str = "hello";

    //正则表达式

    String regex = "[a-zA-Z]{3,5}";

    //输出匹配的结果, 此次匹配返回true。

    System.out.println(str.matches(regex));

}

3). 实现方式3(此种实现方式最快), 匹配11位的电话号码,匹配规则:第一个数字是1,第二个数字是2,3,7,8中任一个,后面9位数字中不包含4。

public void regex3() {

    //要匹配的字符

    String str = "13656231253";

    //正则表达式

    String regex = "1[2378][0-35-9]{9}";

    //将给定的正则表达式编译为模式。 如果匹配需求较多,且需用同相同的regex去匹配,就可将这句写到静态模块里面,用的时候直接使用实例p

    Pattern p = Pattern.compile(regex);

    //创建一个匹配器,匹配给定的输入与此模式。

    Matcher m = p.matcher(str);

    //尝试将整个区域与模式进行匹配。

    boolean flag = m.matches();

    //输出匹配结果,此次结果为true

    System.out.println(flag);

}

2. 替换

public void regexReplace () {

    //要匹配的字符

    String str = "12a6B985Ccv65";

    //正则表达式

    String regex = "[a-zA-Z]+";

    //正则表达式

    String regex2 = "\\d+";

    //将字符串中英文字母替换为&符号,输出12&6&985&65

    System.out.println(str.replaceAll(regex, "&"));

    //将字符串中单个数字或者连续的数字替换为0,输出0a0B0Ccv0

    System.out.println(str.replaceAll(regex2,"0"));

}

3. 切割,根据大写字母切割字符串。

public void outputStr() {

    String str = "oneTtowTthreeDfourJfive";

    String regex = "[A-Z]";

    String[] arr = str.split(regex);

    for (String s: arr) {

    System.out.print(s + " ");

    }

}

下面的对象创建方法中哪些会调用构造方法 ()?

选项B。

“序列化”是一种把对象的状态转化成字节流的机制,“反序列”是其相反的过程,把序列化成的字节流用来在内存中重新创建一个实际的Java对象。这个机制被用来“持久化”对象。

通过对象序列化,可以方便的实现对象的持久化储存以及在网络上的传输。

项D。
为什么需要克隆对象?直接new一个对象不行吗?因为克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。那么我把这个对象的临时属性一个一个的赋值给我新new的对象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了clone是一个native方法,是在底层实现的,运行效率特别高特别快。
常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。
通过clone方法赋值的对象跟原来的对象时同时独立存在的

命令javac-d参数的用途是?()

下面有关java hashmap的说法错误的是?

HashMap通过拉链法解决哈希冲突

设int x=1,float y=2,则表达式x/y的值是:()

基本类型运算时以高精度为标准,低精度的会自动转为高精度的进行运算

本题的意义在于两点,明白这两点之后题会不会本身就不重要了:

①float x = 1;与float x = 1.0f,这两种对于float类型的变量来说定义的方式都是正确的,也是比较常见的笔试题里面考察类型转换的例子,当第一种情况时,是将低精度int向上转型到float,是由于java的特性导致而不需要进行强制转换,而第二种情况则是比较正式的对于float变量的定义,由于这种类型本身在工作项目中并不常见,常用的带小数的数字我们一般都直接使用double类型,而double类型直接定义是没有问题的:double x = 1.0。而由于float的精度没有double类型高,因此必须对其进行显示的格式书写,如果没有这个f,就默认是double类型了。当然double x = 1.0d也是正确的命名,不信你可以尝试,虽然这是一个令人窒息的操作。

②当多个精度的数字同时进行运算时,最终结果以最高精度为准。在多数情况下,整数和小数的各级混合运算中,一般结果都是double类型的。但就本题而言,结果是float类型的,因为x,y两个数字精度最高的就是float,所以最终结果是0.5,并且这个0.5是float类型的。为什么说不是double类型呢,当然如果你这样处理:double m = x/y,当然m是double类型的,也不会报错,而如果你写成int m = x/y,编译器报错提示的时候就会让你转换成float或者进行强制转换成int,他是不会提示你转换成double的,尽管这么写并没有报错,原因就是① 中所说的向上强转。float转换成double不需要任何提示。

下面叙述那个是正确的?()

A选项不需要提前知道所存储对象的类型,默认时Object,

B选项

  • 在Java中,异常通常用于处理错误和异常情况。异常是一种用于传递非正常情况的机制,它允许程序在遇到错误或异常时进行控制流的转移。异常处理是一种用于检测、处理和恢复错误和异常的机制,它允许程序以一种结构化的方式处理这些非正常情况[8]
  • 异常处理的机制可以使代码更加健壮和可靠。它允许开发人员识别和处理潜在的问题,并采取适当的措施来处理它们。然而,使用异常处理机制可能会导致一些系统开销,因为在抛出异常时需要进行一些额外的操作和资源分配[4]

综上所述,使用异常来传递非错误的消息可能会导致更大的系统开销,因为异常处理涉及一些额外的操作和资源分配。但是,异常处理机制对于处理错误和异常情况是非常有用的,可以使代码更加健壮和可靠。因此,开发人员应该根据具体的情况和需求来决定是否使用异常来传递消息。

C选项

  • 在Java中,接口是一种抽象的定义,它定义了一组方法的签名,但没有实现。接口中的方法声明不包含方法体,只有方法的签名。接口可以被类实现,实现类必须提供接口中定义的所有方法的实现[1]
  • 接口中的方法默认是公共的(public),不需要显式地声明为公共。此外,接口中的方法默认是抽象的(abstract),不需要显式地声明为抽象。因此,可以说接口中的方法声明隐含了public和abstract修饰符[6]
  • 然而,接口中不能包含变量声明。在Java中,接口中只能包含常量,这些常量是静态常量(static constants),即公共的(public)、静态的(static)和最终的(final)。常量在接口中的声明通常使用大写字母和下划线命名,例如MAX_VALUE[1]

综上所述,Java接口只能包含函数声明,不能包含变量声明。接口中的方法默认是公共的和抽象的,不需要显式地声明为public和abstract。接口中可以包含常量,这些常量是静态常量。开发人员应该注意接口的定义和用法,以正确地使用接口来实现多态性和代码组织。

D选项

查询java核心卷1知道子类时不能访问父类的私有域,不过可以访问父类的受保护的成员

下列代码片段中,存在编译错误的语句是()

byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7;
b3=(b1+b2);  /*语句1*/
b6=b4+b5;    /*语句2*/
b8=(b1+b4);  /*语句3*/
b7=(b2+b5);  /*语句4*/
System.out.println(b3+b6);

Java中的byte,short,char进行计算时都会提升为int类型。所以1,3,4得到一个int类型赋值给byte就不行。但是final修饰后byte不会转换成int计算,所以2得到的值还是byte

有如下一段代码,请选择其运行结果()

public class StringDemo{
  private static final String MESSAGE="taobao";
  public static void main(String [] args) {
    String a ="tao"+"bao";
    String b="tao";
    String c="bao";
    System.out.println(a==MESSAGE);
    System.out.println((b+c)==MESSAGE);
  }
}

  1. 在第一行代码中,定义了一个名为MESSAGE的私有静态常量,其值为"taobao"。
  2. 在main方法中,首先定义了一个名为a的字符串变量,其值是将"tao"和"bao"拼接而成的"taobao"。由于编译器会对字符串常量进行优化,因此"a"会被直接赋值为编译时确定的"taobao"。
  3. 接下来,定义了两个字符串变量b和c,分别赋值为"tao"和"bao"。
  4. 在第一个输出语句中,比较了a和MESSAGE是否相等。由于a和MESSAGE都是字符串类型,使用"=="比较的是两个字符串对象的引用地址。由于字符串常量在编译时已经确定,所以a和MESSAGE指向的是同一个字符串对象,因此输出结果为true。
  5. 在第二个输出语句中,比较了(b+c)和MESSAGE是否相等。由于b和c都是字符串类型,使用"=="比较的是两个字符串对象的引用地址。由于b和c是两个独立的字符串对象,它们的拼接结果并不是在编译时确定的,而是在运行时通过字符串拼接操作生成的新的字符串对象。因此,(b+c)和MESSAGE指向的是两个不同的字符串对象,输出结果为false。

需要注意的是,字符串的比较应该使用equals()方法,而不是"=="运算符,例如a.equals(MESSAGE)和(b+c).equals(MESSAGE)。equals()方法比较的是字符串的内容是否相等,而"=="运算符比较的是两个对象的引用地址是否相等。

下面说法正确的是?()

•static void yield( ) 导致当前执行线程处于让步状态。如果有其他的可运行线程具有至少与此线程同样高 的优先级,那么这些线程接下来会被调度。注意,这是一个静态方法。

Thread.sleep()方法是线程类Thread的静态方法,调用此方法可以让当前线程暂停执行指定的时间。在休眠期间,当前线程会让出CPU执行时间,给其他线程有机会执行。但是,当前线程持有的对象锁仍然保持,因此在休眠时间结束后,线程会自动恢复,并且继续持有之前的对象锁。

Object.wait()方法是Object类的方法,调用此方法会导致当前线程放弃对象的锁,并进入对象的等待池(wait pool)。等待池中的线程等待被唤醒,只有当其他线程调用了该对象的notify()方法或notifyAll()方法时,等待池中的线程才能进入锁池(lock pool),竞争对象的锁。如果获得了对象的锁,线程就可以进入就绪状态,等待CPU的调度执行。

需要注意的是,在使用wait()方法时,通常要结合synchronized关键字来确保线程安全。因为wait()和notify()方法必须在同步的代码块或同步方法中调用,否则会抛出IllegalMonitorStateException异常。

java语言中,按照一定格式生成程序的文档的工具是?

jar 将许多文件组合成一个jar文件

javac 编译

javadoc 它从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档。

javah 把java代码声明的JNI方法转化成C\C++头文件。 JNI可参考java核心技术卷二第12章

以下叙述正确的是

A错误,类的实例方法是与该类的实例对象相关联的,不能直接调用,只能通过创建超类的一个实例对象,再进行调用 B错误,当父类的类方法定义为private时,对子类是不可见的,所以子类无法调用 C错误,子类具体的实例方法对父类是不可见的,所以无法直接调用, 只能通过创建子类的一个实例对象,再进行调用 D正确,实例方法可以调用自己类中的实例方法

java用()机制实现了线程之间的同步执行

首先jvm中没有进程的概念 ,但是jvm中的线程映射为操作系统中的进程,对应关系为1:1。那这道题的问的就是jvm中线程如何异步执行 。 在jvm中 是使用监视器锁来实现不同线程的异步执行, 在语法的表现就是synchronized 。

有时为了避免某些未识别的异常抛给更高的上层应用,在某些接口实现中我们通常需要捕获编译运行期所有的异常, catch 下述哪个类的实例才能达到目的

要捕获编译时和运行时的所有异常,可以使用java.lang.Exception类的实例来捕获。Exception是所有异常类的基类,它包括了运行时异常和受检异常。通过捕获Exception类的实例,可以捕获所有的异常,无论是编译时异常还是运行时异常。

以下是一个示例的捕获所有异常的代码:

try {
    // 代码块,可能会抛出异常
} catch (Exception e) {
    // 捕获所有异常的处理逻辑
}

在上面的示例中,try代码块中包含了可能抛出异常的逻辑。通过catch语句捕获Exception类的实例,可以捕获所有的异常。在catch代码块中,可以编写处理异常的逻辑。

需要注意的是,捕获所有异常可能会导致对异常的处理变得模糊,因为不同类型的异常通常需要有不同的处理方式。在实际开发中,建议根据具体的需求和情况,选择捕获特定的异常类型,以便可以更好地处理和恢复异常。

要导入java/awt/event下面的所有类,叙述正确的是?()

java.awt.*是导入java\awt包下所有的类,并不包括其子包下的类。

java.awt.event.*才能导入java\awt\event包下的类。

问这个程序的输出结果。

class Base
{
    public void method()
    {
        System.out.println("Base");
    } 
}
class Son extends Base
{
    public void method()
    {
        System.out.println("Son");
    }
     
    public void methodB()
    {
        System.out.println("SonB");
    }
}
public class Test01
{
    public static void main(String[] args)
    {
        Base base = new Son();
        base.method();
        base.methodB();
    }
}

Base base = new Son(); 这句new 了一个派生类,赋值给基类,所以下面的操作编译器认为base对象就是Base类型的 Base类中不存在methodB()方法,所以编译不通过

ArrayList list = new ArrayList(20);中的list扩充几次

ArrayList list=new ArrayList();
这种是默认创建大小为10的数组,每次扩容大小为1.5倍
ArrayList list=new ArrayList(20);

使用的ArrayList的有参构造函数

这种是指定数组大小的创建,创建时直接分配其大小,没有扩充。
一次性为创建了传入的数字的长度的数组
所以,扩充为0次

以下代码可以使用的修饰符是:()

public interface Status {
 /*INSERT CODE HERE*/  int MY_VALUE=10;
 }

接口中属性(字段/全局变量)修饰符:默认为public static final

接口中的方法的修饰符:public abstract

附加知识:

jdk1.8以前接口中不能有可以实现的方法,即没有方法体,里面都是抽象方法

jdk1.8包括(1.8)以后,接口中可以有实现的方法,默认方法+default,静态方法+static。


下面代码运行结果是()

public class Test{ 
    public int add(int a,int b){   
         try {
             return a+b;      
         } 
        catch (Exception e) {  
            System.out.println("catch语句块");
         }
         finally{ 
             System.out.println("finally语句块");
         }
         return 0;
    } 
     public static void main(String argv[]){ 
         Test test =new Test(); 
         System.out.println("和是:"+test.add(9, 34)); 
     }
}

什么不是先输出:和是 finally块 43的原因。

System.out.println("和是:"+test.add(9, 34)); 这是进行字符串拼接是一个整体,所以首先是进入add方法中,进去之后先把先不运算result,而是输出finally块。注意:此时finally块输出结果是:finally语句块,这句话首先打印到控制台中。打印完后返回来执行try中的return得到43,所以此时再将结果与"和是:"进行拼接-->输出:和是 43。所以此时控制台又多了一句话:和是 43。加上之前finally先在控制台上的输出,所以结果为:finally语句块 和是 43.

有以下一个对象:

public class DataObject implements Serializable{
    private static int i=0;
    private String word=" ";
    public void setWord(String word){
        this.word=word;
    }
    public void setI(int i){
        Data0bject.i=i;
     }
}

创建一个如下方式的DataObject:

DataObject object=new Data0bject ( );
object.setWord("123");
object.setI(2);

将此对象序列化为文件,并在另外一个JVM中读取文件,进行反序列化,请问此时读出的Data0bject对象中的word和i的值分别为:

序列化的是对象,不是类,类变量不会被序列化

以下说法错误的是()

1、创建泛型对象的时候,一定要指出类型变量T的具体类型。争取让编译器检查出错误,而不是留给JVM运行的时候抛出类不匹配的异常。 2、JVM如何理解泛型概念 —— 类型擦除。事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。 处理方法很简单,我们叫做类型变量T的擦除(erased) 。 总结:泛型代码与JVM ① 虚拟机中没有泛型,只有普通类和方法。 ② 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除) ③ 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。 无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。

运用泛型编译器不建议使用raw原生类型,而是要指明具体类型List<String>,以便编译器作参数检查。

在编译阶段会采取擦除机制,将所有的泛型都编译成为原生类型List,因为虚拟机中没有泛型,只有普通类和普通方法。

那JVM是如何获取具体类型的呢,答案是强大的反射机制,也正因为有了反射才促生了泛型,所以D错。

-----------------------------------------------------------------------------------------------------

所以,如果你对自己的编程足够自信,你完全可以在写代码的时候只写原生类型而不用泛型,因为其实这只是为了编译器在检查代码的时候防止参数错误,到了编译期泛型都会被擦除,最终还是回到原生类型。

但是,并不建议这么做,因为虽然只写原生类型可以省略编译期泛型擦除这一步,但是这对性能的提升并没起多大哪怕一丁点的作用,反而可能导致我们写代码的时候由于粗心出错了而没有被IDE编译器检查出来,直到运行的时候才报错就得不偿失了。

下列哪些针对代码运行结果的描述是正确的?

class Car extends Vehicle
{
    public static void main (String[] args)
    {
        new  Car(). run();
    }
    private final void run()
    {
        System. out. println ("Car");
    }
}
class Vehicle
{
    private final void run()
    {
        System. out. println("Vehicle");
    }
}

首先final声明的方法是不能被覆盖的,但是这里并不错误,因为方法是private的,也就是子类没有继承父类的run方法,因此子类的run方法跟父类的run方法无关,并不是覆盖。new Car().run()也是调用子类的run方法。

下面赋值语句中正确的是()

A 在Java中,e或E表示科学计数法的指数部分,即以10为底数的指数。例如,5.3e12表示5.3乘以10的12次方。因此,上述代码将d的值设置为530000000000000.0。

B 11.1默认为double转成float属于是向下转型,是需要强转的

C 0.0默认为为double转成float属于是向下转型,是需要强转的

D int 转为 封装类型Double,是无法编译的

Double oD = 3.0, 会把double类型的3.0自动装箱为Double,没有问题

下面几个关于Java里queue的说法哪些是正确的()?

A、LinkedBlockingQueue是一个基于节点链接的可选是否有界的阻塞队列,不允许null值。
B、LinkedBlockingQueue是一个线程安全的阻塞队列,实现了先进先出等特性。
C、PriorityQueue是一个无界队列,不允许null值,入队和出队的时间复杂度是O(log(n))。
D、PriorityQueue是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,该队列的元素遵循FIFO原则。
 

关于 访问权限说法正确 的是 ? ( )

1.成员内部类

(1)该类像是外部类的一个成员,可以无条件的访问外部类的所有成员属性和成员方法(包括private成员和静态成员);

(2)成员内部类拥有与外部类同名的成员变量时,会发生隐藏现象,即默认情况下访问的是成员内部类中的成员。如果要访问外部类中的成员,需要以下形式访问:【外部类.this.成员变量 或 外部类.this.成员方法】;

(3)在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问;

(4)成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象;

(5)内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。如果成员内部类用private修饰,则只能在外部类的内部访问;如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。外部类只能被public和包访问两种权限修饰。

2.局部内部类

(1)局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内;

(2) 局部类不能用 public 或 private 访问说明符进行声明。它的作用域被限定在声明这个局部 类的块中。

例子

public void start0
{
class TiiePrinter inpleients ActionListener
{
public void actionPerforaed(ActionEvent event)
{
Systei.out.println("At the tone, the tine is " + new DateO)
;
if (beep) Toolkit.getDefaul tToolki10•beep():
}
}
ActionListener listener = new TimePrinter();
Timer t = new Timer(interva1, listener);
t.start();
}

3.匿名内部类

(1)一般使用匿名内部类的方法来编写事件监听代码;

(2)匿名内部类是不能有访问修饰符和static修饰符的;

(3)匿名内部类是唯一一种没有构造器的类;

(4)匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

public void start(int interval, boolean beep)
{
ActionListener listener = new ActionListenerO
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is " + new DateO)
;
if (beep) Toolkit.getDefaultToolkit().beep();
}
;}
Timer t = new Timer(interval, listener);
t.start0;
}

4.内部静态类

(1)静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似;

(2)不能使用外部类的非static成员变量或者方法。

在JDK1.7中,下述说法中抽象类与接口的区别与联系正确的有哪些?

阅读如下代码。 请问,对语句行 test.hello(). 描述正确的有()

class Test {
    public static void hello() {
        System.out.println("hello");
    }
}
public class MyApplication {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test test=null;
        test.hello();
    }
}

静态方法属于静态绑定,编译器根据引用类型所属的静态类型为它绑定其对应的方法。此语句会翻译成invokestatic,该指令的调用中不会涉及this,所以不会依赖对象! 还有引用类型=null,其实就是指该引用在堆中没有对应的对象,但是编译的时候还是能根据声明找到其所属的静态类型。
 

在java7中,下列哪个说法是正确的:

A. ConcurrentHashMap使用的是Segement(继承自 ReentrantLock)分段锁的技术来保证同步的,使用synchronized关键字保证线程安全的是HashTable;

B. HashMap实现的是Map接口

C. Arrays.asList方法返回List列表,public static <T> List<T> asList(T... a)

d. SimpleDateFormat查看Java源码可以看到,它的方法都不是Synchronized的,也没有采用其他的同步措施

有关静态初始化块说法正确的是?

java对象初始化顺序 先说结论:

  1. 父类静态代码块,父类静态成员变量(同级,按代码顺序执行)
  2. 子类静态代码块,子类静态成员变量(同级,按代码顺序执行)
  3. 父类普通代码块,父类普通成员变量(同级,按代码顺序执行)
  4. 父类构造方法
  5. 子类普通代码块,子类普通成员变量(同级,按代码顺序执行)
  6. 子类构造方法

注意点:

  1. 静态内容只在类加载时执行一次,之后不再执行。
  2. 默认调用父类的无参构造方法,可以在子类构造方法中利用super指定调用父类的哪个构造方法。


D选项静态内容只在类加载时执行一次,之后不再执行所以不能随时都可以执行

对于上面这段代码,以下说法正确的是:

public class Test
{
    public int x;
    public static void main(String []args)
    {
        System. out. println("Value is" + x);
    }
}

非静态成员只能被类的实例化对象引用,因此这里在静态方法中访问x会造成编译出错

以下程序执行后,错误的结果是()

public class Test {
    private String name = "abc";
    public static void main(String[] args) {
        Test test = new Test();
        Test testB = new Test();
        String result = test.equals(testB) + ",";
        result += test.name.equals(testB.name) + ",";
        result += test.name == testB.name;
        System.out.println(result);
    }
}

首先test.equals(testB),Test类并没有重写equals方法,那么在比较时,调用的依然是Object类的equals()方法,比较的是两个对象在内存中的地址,结果为false。

test.name.equals(testB.name)比较name字符串是否相等,二者都是"abc",结果返回true。

name成员变量并没有被static关键字修饰,那么每个Test类的对象被创建时,都会先执行private String name = "abc";(注意这里使用了直接赋值的方式,没有使用new关键字)。在test对象初始化时,JVM会先检查字符串常量池中是否存在该字符串的对象,此时字符串常量池中并不存在"abc"字符串对象,JVM会在常量池中创建这一对象。当testB被创建时,同样会执行private String name = "abc";,那么此时JVM会在字符串常量池中找到test对象初始化时创建的"abc"字符串对象,那么JVM就会直接返回该字符串在常量池中的内存地址,而不会新建对象。也就是说test.name和testB.name指向的内存是同一个,那么test.name == testB.name返回true。本题正确选项为false,true,true。题目要求选出错误选项,答案为A B C。

java语言的下面几种数组复制方法中,哪个效率最高?

总结:

(1)从速度上看:System.arraycopy > clone > Arrays.copyOf > for

(2)for的速度之所以最慢是因为下标表示法每次都从起点开始寻位到指定下标处(现代编译器应该对其有进行优化,改为指针),另外就是它每一次循环都要判断一次是否达到数组最大长度和进行一次额外的记录下标值的加法运算。

(3)查看Arrays.copyOf的源码可以发现,它其实本质上是调用了System.arraycopy。之所以时间差距比较大,是因为很大一部分开销全花在了Math.min函数上了。

public static byte[] copyOf(byte[] original, int newLength) { byte[] copy = new byte[newLength];
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy;
}

(4)查看System.arraycopy的源码,可以发现它实质上是通过Jni调用本地方法,及c/c++已经编译成机器码的方法,所以快。

public static native void arraycopy(Object src, int srcPos,Object dest, int destPos, int length);

检查程序,是否存在问题,如果存在指出问题所在,如果不存在,说明输出结果。

package algorithms.com.guan.javajicu; 
public class Inc { 
    public static void main(String[] args) { 
       Inc inc = new Inc(); 
       int i = 0; 
       inc.fermin(i); 
       i= i ++; 
       System.out.println(i);
    
    } 
    void fermin(int i){ 
       i++; 
    } 
}

如果你理解JVM的内存模型,就不难理解为什么答案返回的是0,而不是1。 我们单独看问题中的这两句代码。 int i = 0; i = i++; Java虚拟机栈(JVM Stack)描述的是Java方法执行的内存模型,而JVM内存模型是基于“栈帧”的,每个栈帧中都有 局部变量表 和 操作数栈 (还有动态链接、return address等),那么JVM是如何执行这个语句的呢?通过javap大致可以将上面的两行代码翻译成如下的JVM指令执行代码。 0: iconst_0 1: istore_1 2: iload_1 3: iinc 1, 1 6: istore_1 7: iload_1 接下来分析一下JVM是如何执行的: 第0:将int类型的0入栈,就是放到操作数栈的栈顶 第1:将操作数栈栈顶的值0弹出,保存到局部变量表 index (索引)值为1的位置。(局部变量表也是从0开始的,0位置一般保存当前实例的this引用,当然静态方法例外,因为静态方法是类方法而不是实例方法) 第2:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0) 第3:iinc是对int类型的值进行自增操作,后面第一个数值1表示,局部变量表的index值,说明要对此值执行iinc操作,第二个数值1表示要增加的数值。(这时局部变量表index为1的值因为执行了自增操作变为1了,但是操作数栈中栈顶的值仍然是0) 第6:将操作数栈顶的值弹出(值0),放到局部变量表index为1的位置(旧值:1,新值:0),覆盖了上一步局部变量表的计算结果。 第7:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0) 总结:从执行顺序可以看到,这里第1和第6执行了2次将0赋值给变量i的操作(=号赋值),i++操作是在这两次操作之间执行的,自增操作是对局部变量表中的值进行自增,而栈顶的值没有发生变化,这里需要注意的是保存这个初始值的地方是操作数栈而不是局部变量表,最后再将栈顶的值覆盖到局部变量表i所在的索引位置中去。 有兴趣的同学可以去了解一下JVM的栈帧(Stack Frame) 关于第二个陷阱(为什么 fermin方法没有影响到i的值 )的解答看下面。 inc.fermin(i); 1. java方法之间的参数传递是 值传递 而不是 引用传递 2. 每个方法都会有一个栈帧,栈帧是方法运行时的数据结构。这就是说每个方法都有自己独享的局部变量表。(更严谨的说法其实是每个线程在执行每个方法时都有自己的栈帧,或者叫当前栈帧 current stack frame) 3. 被调用方法fermin()的形式参数int i 实际上是调用方法main()的实际参数 i 的一个副本。 4. 方法之间的参数传递是通过局部变量表实现的,main()方法调用fermin()方法时,传递了2个参数: 第0个隐式参数是当前实例(Inc inc = new Inc(); 就是inc引用的副本,引用/reference 是指向对象的一个地址,32位系统这个地址占用4个字节,也就是用一个Slot来保存对象reference,这里传递的实际上是reference的一个副本而不是 reference本身 ); 第1个显示参数是 i 的一个副本。所以 fermin()方法对 i 执行的操作只限定在其方法独享或可见的局部变量表这个范围内,main()方法中局部变量表中的i不受它的影响; 如果main()方法和fermin()方法共享局部变量表的话,那答案的结果就会有所不同。 其实你自己思考一下,就会发现, JVM虚拟机团队这么设计是有道理的

java中下面哪个能创建并启动线程()

public class MyRunnable implements Runnable { 
     public void run() { 
         //some code here 
     } 
 }

对于线程局部存储TLS(thread local storage),以下表述正确的是

同一全局变量或者静态变量每个线程访问的是同一变量,多个线程同时访存同一全局变量或者静态变量时会导致冲突,尤其是多个线程同时需要修改这一变量时,通过TLS机制,为每一个使用该全局变量的线程都提供一个变量值的副本,每一个线程均可以独立地改变自己的副本,而不会和其它线程的副本冲突。

ThreadLocal可以给一个初始值,而每个线程都会获得这个初始化值的一个副本,这样才能保证不同的线程都有一份拷贝。ThreadLocal 不是用于解决共享变量的问题的,不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制.
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值