[核心技术36问]1-12

2023-05-16

 

1.谈谈你对Java平台的理解?“Java是解释执行”,这句话正确吗?

典型回答

Java本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的“书写一次,到处运行”(write once,run anywhere),能够非常容易地获得跨平台能力;另外就是垃圾收集(GC,garbage collection),Java通过垃圾收集器(garbage collector)回收分配内存,大部分情况下,程序员不需要自己操心内存地分配和回收。

我们日常会接触到JRE( Java runtime environment)或者JDK(Java development kit)。JRE,也就是Java运行环境,包含了JVM和Java类库,以及一些模块等。而JDK可以看作是JRE的一个超集,提供了更多工具,比如编译器、各种诊断工具等。

对于“Java是解释执行”这句话,这个说法不太准确。我们开发的Java的源代码,首先通过javac编译成为字节码,然后在运行时通过Java虚拟机内嵌的解释器将字节码转换成最终的机器码。但是常见的JVM,比如我们大多数情况使用的Oracle JDK提供的hotspot JVM,都提供了JIT(just-in-time)编译器,也就是通常所说的动态编译器,JIT能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行,而不是解释执行了。

知识扩展:

回归正题,对于Java平台的理解,可以从很多方面简明扼要地谈一下,例如:Java语言特性,包括泛型、lambda等语言特性;基础类库,包括集合、IO/NIO、网络、并发、安全等基础类库。对于我们日常工作应用较多地类库,面试前系统化总结一下。

或者谈谈JVM地一些基础概念和机制,比如Java的类加载机制,常用版本JDK(JDK8)内嵌的classloader,例如boostrap、application和extension classloader;类加载大致过程:加载、验证、链接、初始化;自定义classloader等。还有垃圾收集的基本原理,最常见的垃圾收集器,如SerialGC、Parallel GC、CMS、G1等,对于适用于什么样的工作负载最好也心里有数。

还有JDK包含哪些工具或者Java领域内其他工具等,如编译器、运行时环境、安全工具、诊断和监控工具等。这些基本工具是日常工作效率的保证。

 

解释执行和编译执行的问题:众所周知,我们通常把Java分为编译期和运行时。这里说的Java的编译和C/C++是有着不同的意义的,javac的编译,编译Java源码生成“.class”文件里面其实是字节码,而不是可以直接执行的机器码。Java通过字节码和Java虚拟机这种跨平台的抽象,屏蔽了操作系统和硬件的细节,这也是实现“一次编译、到处运行”的基础。

在运行时,JVM会通过类加载器加载字节码,解释或者编译执行。就像我前面提到的,主流Java版本中,如JDK8其实是解释和编译混合的一种模式,即所谓的混合模式(-Xmixed)。通常运行在server模式的JVM,会进行上万次调用以收集足够的信息进行高效的编译,clent模式这个门限是1500次。Oracle hotspots JVM内置了两个不同的JIT compiler,C1对应前面说的client模式,适用于对于启动速度敏感的应用,比如普通Java桌面应用;C2对应server模式,它的优化是为长时间运行的服务器端应用设计的。默认是采用所谓的分层编译(tieredcompilation)。

Java虚拟机启动时,可以指定不同的参数对运行模式进行选择。比如,指定“-Xint”,就是告诉JVM只进行解释执行,不对代码进行编译,这种模式抛弃了JIT可能带来的性能优势。毕竟解释器是逐条读入,逐条解释运行的。与其相对应的,还有一个“-Xcomp”参数,这是告诉JVM关闭解释器,不要进行解释执行,或者叫做最大优化级别。但是这种模式也未必是最高效的。“-Xcomp”会导致JVM启动变慢非常多,同时有些JIT编译器优化方式,比如分支预测,如果不进行profiling,往往并不能进行有效优化。

除了我们日常最常见的Java使用模式,其实还有一种新的编译方式,就是所谓的AOT(ahead-of-time compilation),直接将字节码编译成机器代码,这样就避免了JIT预热等各方面的开销,比如Oracle JDK9就引入了实验性的AOT特性,并且增加了新的jaotc工具。把某个类或者某个模块编译成为AOT库。而且,Oracle JDK支持分层编译和AOT协作使用,两者并不是二选一的关系。

 

2.请对比Exception和Error,另外,运行时异常与一般异常有什么区别?

典型回答:

Exception和Error都是继承了Throwable类,在Java中只有Throwable类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。

Exception和Error体现了Java平台设计者对不同异常情况的分类。Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。

Error是指在正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序(比如JVM自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError之类,都是Error的子类。

Exception又分为可检查(checked)异常和不检查(unchecked)异常,可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。不检查异常就是所谓的运行时异常,类似NullPointerException、ArrayIndexOutOfBoundsException之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

考点分析:

NoClassDefFoundError和ClassNotFoundException有什么区别?

https://my.oschina.net/jasonultimate/blog/166932

知识扩展:

      如下代码:

    try{
	Thread.sleep(10001);
    }catch(Exception e){
	//ignore it
    }

这段代码违反了异常处理的两个基本原则,第一,尽量不要捕获类似Exception这样的通用异常,而是应该捕获特定异常,在这里是Thread.sleep()抛出的InterruptedException。这是因为在日常的开发和合作中,我们读代码的机会往往超过写代码,软件工程是门协作的艺术,所以我们有义务让自己的代码能够直观地体现出尽量多的信息,而泛泛的Exception之类,恰恰隐藏了我们的目的。另外,我们也要保证程序不会捕获到我们不希望捕获的异常。比如,你可能更希望RuntimeException被扩散出来,而不是被捕获。第二,不要生吞异常。这是异常处理中要特别注意的事情,因为很可能会导致非常难以诊断的诡异情况。生吞异常,往往是基于假设这段代码可能不会发生,或者感觉忽略异常是无所谓的,但是千万不要在产品代码做这种假设!

如果我们不把异常抛出来,或者也没有输出到日志之类,程序可能在后续代码以不可控的方式结束。没人能够轻易判断究竟是哪里抛出了异常,以及是什么原因产生了异常。

    请看如下代码:

try{
	//业务代码
}catch(Exception e){
	e.printStackTrace();
}

这段代码作为一段实验代码,它是没有任何问题的,但是在产品代码中,通常都不允许这样处理。

printStackTrace()的文档,开头就是“Prints this throwable and its backtrace to the standard error stream”.问题就在这里,在稍微复杂一点的生产系统中,标准出错(STERR)不是个合适的输出选项,因为你很难判断出到底输出到哪里去了。

尤其是对于分布式系统,如果发生异常,但是无法找到堆栈轨迹,这纯属是为诊断设置障碍。所以,最好使用产品日志,详细地输出到日志系统里。

我们接下来看下面的代码段,体会一下throw early,catch late原则。

代码如下:

public void readPreference(String fileName){
    //perform operations
    InputStream in=new InputStream(fileName);
    //read the preferences file
}

如果filename是null,程序就会抛出NullPointerException,但是由于没有第一时间暴露出问题,堆栈信息可能非常令人费劲,往往需要相对复杂的定位。这个NPE只是作为例子,在实际产品代码中,可能是各种情况,比如获取配置失败之类的。在发现问题的时候,第一时间抛出,能够更加清晰地反映问题。

我们可以修改一下,让问题“throw early”,对应的异常信息就非常直观了。

代码如下:

public void readPreference(String fileName){
    Object.requireNonNull(fileName);
    //perform operations
    InputStream in=new InputStream(fileName);
    //read the preferences file
}

至于“catch late”,其实是我们经常苦恼的问题,捕获异常后,需要怎么处理呢?最差的处理方式,就是生吞异常,本质上其实是掩盖问题。如果实在不知道如何处理,可以选择保留原有异常的cause信息,直接再抛出或者构建新的异常抛出去。在更高层面,因为有了清晰的(业务)逻辑,往往会更清楚合适的处理方式是什么。

 

从性能角度来审视一下java的异常处理机制,这里有两个可能会相对昂贵的地方:

(1)try-catch代码段会产生额外的性能开销,或者换个角度说,它往往会影响JVM对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的try包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句要低效。

(2)java会实例化一个Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。

所以,对于部分追求极致性能的底层类库,有种方式是尝试创建不进行栈快照的Exception。这本身也存在争议,因为这样做的假设在于,我创建异常时知道未来是否需要堆栈。问题是,实际上可能吗?小范围或许可能,但是在大规模项目中,这么做可能不是个理智的选择。如果需要堆栈,但又没有收集这些信息,在复杂情况下,尤其是类似微服务这种分布式系统,这会大大增加诊断的难度。

当我们的服务出现反应变慢、吞吐量下降的时候,检查发生最频繁的Exception也是一种思路。

 

 

3.谈谈final、finally、finalize有什么不同?

  • final 修饰符(关键字)

如果一个类被final修饰,意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能既被声明为abstract,又被声明为final。
如果一个方法被final修饰,意味着它只能被使用,不能被重写(override)。
如果一个变量被final修饰,意味着它在使用过程中,不可以被改变。而且,被final修饰的变量的初始化有两种方式:1、在final变量定义时直接给其赋值;2、在构造器中。这两个地方只能任选其一,不能同时赋值。

  • finally

    在异常处理时提供finally块来执行任何清除操作。如果抛出一个异常,那么相匹配的catch字句就会执行,然后控制就会进入finally块(如果有的话)。就算不抛出异常,如果有finally块,也是会执行的。

  • finalize

    finalize是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。这个方法是在垃圾收集器在确定了,被清理对象没有被引用的情况下调用的。finalize是在Object类中定义的,因此,所有的类都继承了它。子类可以覆盖finalize()方法,来整理系统资源或者执行其他清理工作。

 

4.强引用、软引用、弱引用、幻象引用有什么区别?

 

    不同的引用类型,主要体现的是对象不同的可达性状态和对垃圾收集的影响。

    所谓强引用,就是我们常见的普通的对象引用,只要还有强引用指向一个对象,就能表明该对象还活着,垃圾收集器就不会碰这种对象。对于一个普通对象,如果没有其他的引用关系,只要超出了引用的作用域或者显式地将引用值赋为null,那么垃圾收集器就可以收集这种引用了。当然,在收集的时候还是要具体根据垃圾收集策略来收集。

    软引用,是一种相对于强引用弱化一些的引用,它可以使对象豁免一些内存收集。只有当内存不足时,JVM才会试图去回收软引用指向的对象,JVM会在抛出OutOfMemoryError之前回收软引用指向的对象。软引用通常用来实现内存敏感的缓存,在还有空闲内存时,就会暂时保留缓存,在内存不够时清理掉,这样就确保了使用缓存的同时,不会耗尽内存。

    弱引用,不会使对象豁免垃圾收集,它仅仅是提供一种对弱引用状态下对象的访问途径。可以用来构建一种没有特定约束的关系,比如维护一种非强制性映射的关系,如果要使用对象的时候,对象还存在,那么就使用它,如果不存在那么创建新的实例。弱引用也经常用来实现缓存。

    对于幻象引用,也叫做虚引用,并不能通过它来访问对象,它仅仅是提供了一种确保对象在被finalize()以后,做某些事情的机制。比如,通常用来做所谓的Post-Mortem清理机制,也有人利用幻象引用监控对象的创建和销毁。

 

5.String、StringBuffer、StringBuilder有什么区别?

    String是java语言非常重要和基础的类,提供了构造和管理字符串的各种基本逻辑。String是典型的immutable类,所以被声明为final类型,所有属性也都是final的。正因为它的不可变性,所以剪裁拼接字符串都会产生新的String对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用程序有明显影响。

    StringBuffer是为解决上面提到的拼接字符串产生过多中间对象而提出的一个类。它可以用append或者add方法把字符串添加到已有序列的末尾或者指定位置。StringBuffer本质是一个线程安全的可修改字符序列,会产生额外的性能开销,所以除非有实现线程安全的需要,否则推荐使用StringBuilder。

    StringBuilder是Java1.5中新增的,在能力上和StringBuffer没有区别,但是它去掉了线程安全的部分,所以减少了很多性能开销,是绝大部分情况下进行字符串拼接的首选。

 

6.动态代理是基于什么原理?

    Java是静态的强类型语言,但是因为提供了类似反射等机制,也具备了部分动态类型语言的能力。

    反射机制是Java语言提供的一种基础功能,赋予程序在运行时自省的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。

    动态代理是一种方便运行时构建代理,动态代理代理方法调用的机制。很多场景都是利用类似机制做到的,比如用来包装RPC调用,面向切面的编程(AOP)。

    实现动态代理的方式很多,比如JDK自身提供的动态代理就是利用上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似ASM,cglib(基于ASM),javassist等。

 

7.int和Integer有什么区别?

    int是我们常说的整型数字,是Java语言8个基本数据类型(byte,short,int,long,float,double,char,boolean)之一。Java语言虽然号称一切都是面向对象的,但原始数据类型是例外。

    Integer是int对象的包装类型,他有一个int类型的字段存储数值,并且提供了基本操作,比如数学运算、以及和其他类型相互转换等。在Java 5中还提供了自动装箱自动拆箱功能,Java语言会根据上下文,进行自动转换,极大地简化了相关编程。

    关于Integer的值缓存,这涉及到Java 5中另一个改进。一般在构造的时候都是调用构造器直接new一个对象,但是在实践中我们发现,大部分数据操作都是集中在有限的、较小的数据范围,因而在Java 5中新增了一个静态工厂方法valueOf,在调用他的时候会利用一个缓存机制,极大提高了性能。按照Java doc,这个值默认缓存是-128——127。

 

8.对比Vector、ArrayList、LinkedList有何区别?

    这三者都是实现集合框架中的List,也就是所谓的有序集合,因此具体功能实现也类似。比如都提供按照位置进行定位、添加、删除的操作,都提供迭代器以遍历其内容。但因为具体的设计区别,在行为、性能、线程安全等方面,表现又有很大不同。

    Vector是Java早期提供的线程安全的动态数组,如果没有线程安全的需求,并不建议使用,毕竟线程安全需要额外的性能开销。Vector底层是通过对象数组来存储数据的,可以根据需要自动地增加容量。如果Vector已满需要扩容,则会新建一个数组,并把原来数组的内容拷贝过去。(当数组已满时,会创建新的数组,并拷贝原有数组数据。)

    ArrayList是应用更加广泛的动态数组,它不是线程安全的,所以性能要好很多。与Vector一样,ArrayList也可以根据需要扩容,不过,扩容逻辑有所区别,Vector每次扩容容量会增加一倍,ArrayList增加50%。

    LinkedList顾名思义是Java提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的。

 

Java提供的默认排序算法,具体是什么排序方式以及设计思路等:

    需要区分是Arrays.sort()还是Collections.sort()(底层是调用Arrays.sort());什么数据类型;多大的数据集(太小的数据集,复杂排序是没必要的,Java会直接进行二分插入排序)等。

    对于原始数据类型,目前使用的是双轴快速排序(Dual-PivotQuickSort),是一种改进的快速排序算法,早期版本是相对传统的快速排序。

    对于对象数据类型,目前使用的是TrimSort,思想上也是一种归并排序和二分插入排序结合的优化排序算法。这个并不是java的独创,简单来说它的思路就是查找数据集中已经排好序的分区(这里叫run),然后合并这些分区来达到排序的目的。

    java 8引入了并行排序算法(直接使用parallelSort方法),这是为了充分利用现代多核处理器的计算能力,底层实现基于fork-join框架,当处理的数据集比较小的时候,差距不明显,甚至还表现力差一点,但是,当数据集增长到数百万或百万以上时,提高就非常大了,具体还是取决于处理器和系统环境。

 

9.对比HashTable、HashMap、TreeMap有什么不同?

    HashTable、HashMap、TreeMap都是最常见的一些Map实现,是以键值对的形式存储和操作数据的容器类型。

    HashTable是早期java类库提供的Hash表实现,本身是同步的,不允许null键和值,且因为同步造成的性能开销,已经不提倡使用;

    HashMap是应用更加广泛的哈希表实现,行为上大致与HashTable差不多,主要区别在于HashMap不是同步的,且允许null键和值。通常情况下,HashMap的put和get操作都可以在常数时间内完成,所以它是实际情况中需要用键值对存取数据的首选,比如,实现一个用户ID和用户信息对应的运行时存储结构。

    TreeMap则是基于红黑树的一种按顺序访问的Map,与HashMap不同的是,它的put、get、remove操作都是O(log(n))的时间复杂度,具体顺序可以由指定的Comparator来指定,或者根据键的自然顺序来判定。

扩展:LinkedHashMap和TreeMap:

    LinkedHashMap:遍历顺序符合插入顺序,实现是通过为键值对创建一个双向链表;

    TreeMap:整体顺序是由键的顺序关系决定的,通过Comparator或者Comparable来决定。

 

10.如何保证容器是线程安全的?ConcurrentHashMap如何实现高效的线程安全?

    java提供了不同层面的线程安全支持。在传统集合框架内部,提供了HashTable等同步容器,还提供了所谓的同步包装器(synchronized Wrapper),也可以通过调用Collcetions工具类提供的包装方法来获取一个同步的包装容器,比如调用Collections.synchronizedMap来创建线程安全的Map,但是它们都是利用粗粒度的同步方式来保证线程安全,在高并发的情况下,性能会比较低下。

    另外,更加普遍的选择是利用并发包提供的各种线程安全容器类,它提供了:

    各种并发容器,如ConcurrentHashMap、CopyOnWriteArrayList等;

    各种线程安全的队列(Queue、Deque),如ArrayBlockingQueue,SynchronousQueue等;

    各种有序容器的线程安全版本等。

    具体保证线程安全的方式,有简单的synchronize实现,到更加精细的并发包内的线程安全实现,比如基于锁分离的ConcurrentHashMap等并发容器的实现。具体选择要看开发的场景需求,总体来说,并发包内提供的容器通用场景,远优于简单同步实现。

 

11.java提供了哪些IO方式?NIO如何实现多路复用?

    java IO方式有很多种,基于不同的IO抽象模型和交互方式,可以进行简单区分。

    首先,传统的java.io包,它是基于流模型实现,提供了我们最熟知的一些IO功能,比如输入输出流、File抽象等。交互方式是同步、阻塞的方式,也就是说,在读取输入流或者写入输出流时,在读、写动作完成之前,线程会一直阻塞在那里,它们之间的调用是可靠的线性顺序。

    java.io包的好处是代码比较简单、直观,缺点是IO和扩展性存在局限性,容易造成性能瓶颈。

    很多时候,人们把java.net下面的部分API,比如socket、serversocket、HttpURLConnection也归类到同步阻塞IO类库中,因为网络通信同样是IO行为。

    第二,在java1.4中引入了NIO框架(java.nio包),提供了buffer、selector、channel等新的抽象,可以构建多路复用的、同步非阻塞IO程序,同时提供了更接近操作系统底层的高性能数据操作方式。

    第三,在java 7中,NIO有了进一步改进,也就是NIO2,引入了异步非阻塞IO方式,也有很多人叫它AIO(Asynchronous IO),异步IO操作基于事件和回调机制,可以简单理解为,应用操作直接返回,而不会阻塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续工作。

 

12.Java有几种文件拷贝方式?哪一种最高效?

    java有多种比较典型的文件拷贝实现方式,比如:

    利用java.io类库,直接为源文件构建一个FileInputStream读取,然后再为目标文件构建一个FileOutputStream,完成写入工作。

public static void copyFileByStream(File source,File dest) throws IOException{
    	try(InputStream is=new FileInputStream(source);
    			OutputStream os=new FileOutputStream(dest);){
    		byte[] buffer=new byte[1024];
    		int length;
    		while((length=is.read(buffer))>0){
    			os.write(buffer, 0, length);
    		}
    	}
    }

    或者利用java.nio类库提供的transferTo或transferFrom方法实现。

public static void copyFileByChannel(File source,File dest) throws IOException{
    	try(FileChannel sourceChannel=new FileInputStream(source).getChannel();
    			FileChannel targetChannel=new FileOutputStream(dest).getChannel();){
    		for(long count=sourceChannel.size();count>0;){
    			long transferred=sourceChannel.transferTo(sourceChannel.position(), count, targetChannel);
    			count-=transferred;
    		}
    	}
    	
    }

    当然,java标准类库本身已经提供了几种Files.copy的实现。对于copy的效率,这个其实与操作系统和配置等情况相关,总体上来说,NIO transferTo/From 的方式可能更快,因为它更能利用现代操作系统的底层机制,避免不必要的拷贝和上下文切换。

扩展:如何提高类似拷贝等IO操作的性能?

(1)在程序中,使用缓存原则,合理减少IO次数(在网络通信中,如TCP传输,window大小也可以看作类似思路)。

(2)使用transferTo等机制,减少上下文切换和额外IO操作。

(3)尽量减少不必要的转换过程,比如编解码;对象序列化和反序列化,比如操作文本文件或者网络通信,如果不是过程中需要使用文本信息,可以考虑不要将二进制信息转换成字符串,直接传输二进制信息。

 

    

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[核心技术36问]1-12 的相关文章

随机推荐

  • 一条sql语句添加多个字段

    Forbiden Merge the alter statement for table 39 app info 39 to ONE 需要给表中添加两个字段 xff0c 之前写了两句 xff1a alter table app info a
  • MySql集群搭建

    分布式 集群都是用来处理大批量数据操作的 xff0c 工作原理不太一样 分布式是缩短每个任务的执行时间来提升工作效率 xff0c 集群是提高单位时间内执行的任务数来提高效率 分布式是将步骤分到不同机器上 xff0c 集群指的是几个任务同时处
  • mabatis Mapper.xml报错

    org springframework jdbc BadSqlGrammarException Error querying database Cause com mysql jdbc exceptions jdbc4 MySQLSynta
  • 不同Java版本切换

    export JAVA HOME 61 user local jdk 11 0 5 export PATH 61 JAVA HOME bin PATH export CLASSPATH 61 JAVA HOME lib dt jar JAV
  • spring 事务不生效问题 bmw-jade-route事务配置

    在spring中配置了事务 xff0c 但是没有生效 64 Transactional rollbackFor 61 Exception class public Long insertTicket Ticket ticket List l
  • springboot 拦截器返回json字符串给前端页面

    在intercept中加入以下代码 xff1a private void returnJson HttpServletResponse response String json PrintWriter writer 61 null resp
  • 一句老话:学习贵在坚持,开始学习《Asp.net 程序设计》

    买Asp net书已经一年多了 xff0c 一年来总是为了工作忙忙碌碌 xff0c 书却没有好好看 最近终于可以有时间看书了 xff0c 翻了几页 xff0c 里面有我去年看书的笔记 xff0c 日期是2004 3 12日 看来已经是整整过
  • springboot注解拦截器不生效问题

    今天用springboot写了一个注解拦截器 xff0c 一直不生效 xff0c 网上各种方式我都尝试过了 xff0c 都不起作用 xff0c 找了好久总算知道是什么原因了 我的annotation xff1a 64 Inherited 6
  • springboot pom.xml 配置不替换问题

    今天遇到了一个问题 xff0c 在Pom中配置的变量在编译时没有自动替换 properties文件和 xml文件中的 key xff0c 后来发现原因是因为我在pom里面写了 xff1a 进入starter parent的pom以后发现 x
  • 项目启动报错:Caused by: java.lang.IncompatibleClassChangeError: Implementing class at java.lang.ClassLoad

    项目启动报错 xff1a Caused by java lang IncompatibleClassChangeError Implementing class at java lang ClassLoader defineClass1 N
  • resin服务本地调试

    在项目he project下建两个文件夹 xff0c 分别为resin和webapp 安装的resin放在resin文件夹中 xff0c resin文件夹如下 conf resin xml配置如下 xff1a lt Resin 4 0 co
  • 1机器学习基础—2统计学习方法概论

    一 机器学习基础 1 监督学习一般使用两种类型的目标变量 xff1a 标称型和数值型 在分类算法中目标变量的类型通常是标称型的 xff0c 而在回归算法中通常是连续性的 2 分类和回归都属于监督学习 分类是将实例数据划分到合适的分类中 xf
  • 2感知机

    1 感知机是二类分类的线性分类模型 xff0c 其输入为实例的特征向量 xff0c 输出为实例的类别 xff0c 取 43 1和 1二值 感知机对应于输入空间 xff08 特征空间 xff09 中将实例划分为正负两类的分离超平面 xff0c
  • [leetcode]大可日常打卡1

    344 Reverse String class Solution public String reverseString String s if s 61 61 null s length 61 61 0 return s StringB
  • [leetcode]大可日常打卡2

    804 Unique Morse Code Words 先把所有的字母以及对应的morse code存储到map里面 xff0c 然后对于words的每一个 xff0c 把对应的transformation存储到一个hashmap里面 xf
  • [2017校招]大可打卡1

    1 网易 合唱团 import java util Scanner public class Main public static void main String args Scanner sc 61 new Scanner System
  • [leetcode]大可日常打卡-树

    687 最长同值路径 一开始非常没有思路 看了解析以后 xff0c 找到了思路 xff0c 把长度看作是从一个节点向左右子树延伸出去的两个箭头 xff0c 从下往上遍历 xff0c 后序遍历递归 xff0c 如果箭头上的值等于节点的值 xf
  • 解决:Failed to download metadata for repo ‘base‘: Cannot download repomd.xml: Cannot download repodata

    1 先查看本机的系统信息 root 64 h0436 h0436 zlong cat etc redhat release 2 进入yum repos d root 64 h0436 zlong cd etc yum repos d 3 查
  • [剑指offer]大可日常打卡-树

    8 二叉树的下一个节点 给定一个二叉树和其中的一个结点 xff0c 请找出中序遍历顺序的下一个结点并且返回 注意 xff0c 树中的结点不仅包含左右子结点 xff0c 同时包含指向父结点的指针 思路 xff1a 中序遍历 xff0c 左根右
  • [核心技术36问]1-12

    1 谈谈你对Java平台的理解 xff1f Java是解释执行 xff0c 这句话正确吗 xff1f 典型回答 xff1a Java本身是一种面向对象的语言 xff0c 最显著的特性有两个方面 xff0c 一是所谓的 书写一次 xff0c