小码农的十万个为什么!!!(二)

《小码农的十万个为什么!!!(一)》
《小码农的十万个为什么!!!(二)》

1.@Autowired 与@Resource的区别

原文很棒:
https://blog.csdn.net/weixin_40423597/article/details/80643990
  @Resource的作用相当于@Autowired,只不过**@Autowired按byType自动注入**,而**@Resource默认按 byName自动注入**罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
  3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
  4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
@Autowired 与@Resource的区别:
1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:

@Autowired () @Qualifier ( "baseDao" )
private BaseDao baseDao;

3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

@Resource (name= "baseDao" )
private BaseDao baseDao;

推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

2.Java中native关键字

参考《Java中native关键字》
  native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
  JNI是Java本机接口(Java Native Interface),是一个本机编程接口,它是Java软件开发工具箱(Java Software Development Kit,SDK)的一部分。JNI允许Java代码使用以其他语言编写的代码和代码库。Invocation API(JNI的一部分)可以用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而允许程序员从本机代码内部调用Java代码。
JNI的书写步骤如下:
a.编写带有native声明的方法的Java类
b.使用javac命令编译编写的Java类
c.使用java -jni ****来生成后缀名为.h的头文件
d.使用其他语言(C、C++)实现本地方法
e.将本地方法编写的文件生成动态链接库

3.Java中的equals()和==比较

equals()是判断两个变量或者实例指向同一个内存空间的值是不是相同
==是判断两个变量或者实例是不是指向同一个内存空间
举个通俗的例子来说,双等号是判断两个人是不是住在同一个地址,而equals是判断同一个地址里住的人是不是同一个。

实例解析:

public class EqualsTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Integer aaa=new Integer(5);
        Integer bbb=new Integer(5);
        
        int a=10;
        int b=10;
        String str1=new String("justice");
        String str2=new String("justice");
        String str3;
        str3=str1;

        System.out.println(aaa==bbb);//false
        System.out.println(aaa.equals(bbb));//true
        System.out.println(a==b);//true
        
        System.out.println(str1==str2);//false
        System.out.println(str1.equals(str2));//ture
        
        System.out.println(str1==str3);//ture
        System.out.println(str1.equals(str3));//ture
    }
}

4.Mybatis获取实际执行的sql语句

有时候我们需要知道我们正在执行的sql是什么,或者将它写入日志,或者统计分析sql的执行时间,这里都会要求我们获取执行的SQL。

//这里面值填了一个参数,这个参数的意思是:com.demo.db.mapper.DemoMapper是xml文件里的namespace路径。
//insert是你的id,即<insert id="insert">
String sql = sqlSessionFactory.getConfiguration().getMappedStatement("com.demo.db.mapper.DemoMapper.insert").getBoundSql().getSql();

sqlSessionFactory该如何获取呢?一般的,如果配置了mybatis mapper 扫描器,就可以直接在代码中注入进来,即
@Autowired
private SqlSessionFactory sqlSessionFactory;

getConfiguration()

public Configuration getConfiguration() {
        return this.sqlSessionFactory.getConfiguration();
}

getMappedStatement()

public MappedStatement getMappedStatement(String id) {
        return this.getMappedStatement(id, true);
}

getBoundSql()

public BoundSql getBoundSql(Object parameterObject) {
        BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings == null || parameterMappings.isEmpty()) {
            boundSql = new BoundSql(this.configuration, boundSql.getSql(), this.parameterMap.getParameterMappings(), parameterObject);
        }

        Iterator var4 = boundSql.getParameterMappings().iterator();

        while(var4.hasNext()) {
            ParameterMapping pm = (ParameterMapping)var4.next();
            String rmId = pm.getResultMapId();
            if (rmId != null) {
                ResultMap rm = this.configuration.getResultMap(rmId);
                if (rm != null) {
                    this.hasNestedResultMaps |= rm.hasNestedResultMaps();
                }
            }
        }

        return boundSql;
}

5.NullPointerException异常但堆栈不打印,找不到具体哪一行?

你或许遇到过日志打印的时候,只会提示一个空指针异常,但不会提示哪里的代码抛出了这个异常,导致我们不能很快定位问题所在。
问题原因:
这是虚拟机做的优化,堆栈信息给忽略了,如果想要打印出堆栈信息,需要在 java 虚拟机启动的时候加一个虚拟机参数,这个虚拟机参数是:

-XX:-OmitStackTraceInFastThrow

修改过后,果然打印出了堆栈信息,确定了是哪一行抛出的错,结合代码和数据最终修复了 bug 。

6.修改虚拟机参数?

方式一 :IDEA中修改
1.Run–>Edit Configurations
2.选中要添加JVM参数的Application,然后在Configuration里面的VM options中输入想要添加的系统参数。
注意:针对所有的Application设置
(1)找到IDEA安装目录中的bin目录
(2)找到idea.exe.vmoptions文件
(3)打开该文件编辑并保存
优先级关系:代码中的配置>Application中的配置>全局配置

方式二:命令处理
java虚拟机可以使用JAVA_HOME/bin/java程序启动(JAVA_HOME为JDK的安装目录),
一般来说,java进程的命令使用方法如下:
java [-options] class [args…] ,[]代表可选
其中,-options 表示java虚拟机的启动参数,class 为带有main()方法的java类,args表示传递给主函数main()的参数.
实例:

public class Demo1 {
    public static void main(String[] args) {
        for(int i=0;i<args.length;i++){
            System.out.println("参数"+(i+1)+":"+args[i]);
        }
        System.out.println("-Xmx "+Runtime.getRuntime().maxMemory()/1024/1024+"M");
    }
}

运行结果:

参数1:a
-Xmx 30M

7.@Reference 、@Resource和@Autowired的简单理解

(1)@Autowired

org.springframework.beans.factory.annotation.Autowired

SpringBoot项目中常用。简单来说就是引入由Spring容器管理的bean。
(2)@Resource

javax.annotation.Resource

作用相当于@Autowired,只不过@Autowired是byType自动注入,而@Resource默认byName自动注入。
(3)@Reference

com.alibaba.dubbo.config.annotation.Reference

@Reference是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,需要dubbo配置使用。
简单来说他们的区别:
@Reference注入的是分布式中的远程服务对象,@Resource和@Autowired注入的是本地spring容器中的对象。

8.@PostContruct和@PreDestroy

从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct和@PreDestroy,这两个注解被用来修饰一个非静态的void()方法。
(1)@PostContruct
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
(2)@PreDestroy
被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前。
(3)执行顺序
Constructor==>@Autowired==>postConstruct==>initdestory>predestory==卸载servlet

9.Spring Boot 配置加载顺序及属性加载顺序

https://www.jb51.net/article/146324.htm

10.Springboot中注册bean的方式

spring在启动时会自己把bean(java组件)注册到ioc容器里,实现控制反转,在开发人员使用spring开发应用程序时,你是看不到new关键字的,所有对象都应该从容器里获得,它们的生命周期在放入容器时已经确定!
(1)@ComponentScan
Spring容器会扫描@ComponentScan配置的包路径,找到标记@Component注解的类加入到Spring容器。
效果等同于XML配置文件中的<context:component-scan base-package=“包名”>
注意:java8之后一个类可以标记多个@ComponentScan扫描规则

实例:

@ComponentScan(basePackages = {
        "io.xxx.web.core.component",
        "io.xxx.web.core.events",
        "io.xxx.web.admin",
}, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
                JsonExceptionResolver.class,
        })
})
//includeFilters,指定扫描导入类型的过滤规则,类型为Filter[];
//excludeFilters,指定扫描排除类型的过滤规则,类型为Filter[]。

(2)@Bean
标记在方法上,将方法返回值注册到Spring容器,类型为返回值类型,id默认为方法名。注解@Bean被声明在方法上,方法都需要有一个返回类型,而这个类型就是注册到IOC容器的类型,接口和类都是可以的,介于面向接口原则,提倡返回类型为接口。

效果等同于XML配置文件中的

实例:

@Configuration
public class LogServiceConfig {

  /**
   * 扩展printLogService行为,直接影响到LogService对象,因为LogService依赖于PrintLogService.
   *
   * @return
   */
  @Bean
  public PrintLogService printLogService() {
    return new PrintLogServiceImpl();
  }

  @Bean
  public EmailLogService emailLogService() {
    return new EmailLogServiceImpl();
  }

  @Bean
  public PrintLogService consolePrintLogService() {
    return new ConsolePrintLogService();
  }
}

(3)@Import
这种方法最为直接,直接把指定的类型注册到IOC容器里,成为一个java bean,可以把@Import放在程序的入口,它在程序启动时自动完成注册bean的过程。
实例:

@Import({ LogService.class,PrintService.class })
public class RegistryBean {

}

11.Springboot中通过ApplicationContext.getBeanOfType(EventListener.class)获取到了对象,但EventListener接口是空的并没有被任何注解注释,不过它的实现类都用了@Component注解,这是怎么回事?

一般我们都会认为被@Component注解标注的类都会被注入到Spring的bean容器中,这里其实就是用接口引用接收接口实现类对象的一种Java多态的实现。我们用EventListener接口来接收它的实现类对象,而它的实现类都已经正常注入到了bean容器中,这里用ApplicationContext自然能够获取到对象。

12.Java中遍历HashMap的方式

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class Main {
    public static void main(String[] args) {
        hash();
    }
    public static void hash(){
        HashMap<Integer,String> map = new HashMap();
        map.put(1,"a");
        map.put(2,"b");
        map.put(3,"c");
 
        //方法1,lambda,最简洁高效
        map.forEach((k,v) -> System.out.println("key: "+k+","+"value: "+v));
 
        //方法2,常用高效
        for(Map.Entry<Integer,String> entry:map.entrySet()){
            System.out.println("key: "+entry.getKey()+","+"value: "+entry.getValue());
        }
 
        //方法3,分开使用
        for (Integer key : map.keySet()) {
            System.out.println("Key: " + key);
        }
        for (String value : map.values()) {
            System.out.println("Value: " + value);
        }
 
        //方法4 迭代器遍历
        Iterator<Map.Entry<Integer, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<Integer, String> entry = entries.next();
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
 
        //方法5,最低效
        for (Integer key : map.keySet()) {
            String value = map.get(key);
            System.out.println("Key: " + key + ", Value: " + value);
        }
 
    }
}

13.常用的maven命令收集

(1)mvn compile 编译,将Java 源程序编译成 class 字节码文件。
(2)mvn test 测试,并生成测试报告
(3)mvn clean 将以前编译得到的旧的 class 字节码文件删除
(4)mvn pakage 打包,动态 web工程打 war包,Java工程打 jar 包。
(5)mvn install 将项目生成 jar 包放在仓库中,以便别的模块调用

14.为什么Java的构造方法不能被重写但是可以被重载?

重写是子类方法重写父类的方法,重写的方法名不变,而类的构造方法名必须与类名一致,假设父类的构造方法如果能够被子类重写则子类类名必须与父类类名一致才行,所以 Java 的构造方法是不能被重写的。

15.new String()创建的是几个对象?

String str1 = "abc";  // 在常量池中

String str2 = new String("abc"); // 在堆上

解析如下:
  当直接赋值时,字符串“abc”会被存储在常量池中,只有1份,此时的赋值操作等于是创建0个或1个对象。如果常量池中已经存在了“abc”,那么不会再创建对象,直接将引用赋值给str1;如果常量池中没有“abc”,那么创建一个对象,并将引用赋值给str1。
  那么,通过new String(“abc”);的形式又是如何呢?答案是1个或2个。
  当JVM遇到上述代码时,会先检索常量池中是否存在“abc”,如果不存在“abc”这个字符串,则会先在常量池中创建这个一个字符串。然后再执行new操作,会在堆内存中创建一个存储“abc”的String对象,对象的引用赋值给str2。此过程创建了2个对象
  当然,如果检索常量池时发现已经存在了对应的字符串,那么只会在堆内创建一个新的String对象,此过程只创建了1个对象。

16.线程的几种状态

在这里插入图片描述
新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)、死亡状态(Dead)
一次面试尽然忘了说新建状态,我丢。

17.Java中 boolean数据类型到底占几个字节??

布尔类型定义:
  布尔数据类型只有两个可能的值:真和假。使用此数据类型为跟踪真/假条件的简单标记。这种数据类型就表示这一点信息,但是它的“大小”并不是精确定义的。也就是说,java规范中,没有明确指出boolean的大小。
有如下三种说法:
(1)1个bit(1/8个字节)
  理由:boolean类型的值只有true和false两种逻辑值,在编译后会使用1和0来表示,这两个数在内存中按位算,仅需1位(bit)即可存储,位是计算机最小的存储单位。。
(2)1个字节
  理由:虽然编译后1和0只需占用1位空间,但计算机处理数据的最小单位是1个字节,1个字节等于8位,实际存储的空间是:用1个字节的最低位存储,其他7位用0填补,如果值是true的话则存储的二进制为:0000 0001,如果是false的话则存储的二进制为:0000 0000。
(3)4个字节
  理由:在《Java虚拟机规范》一书中的描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。也就是说JVM规范指出boolean当做int处理,也就是4字节,boolean数组当做byte数组处理,这样我们可以得出boolean类型占了单独使用是4个字节,在数组中是确定的1个字节
总结:
  java规范中,没有明确指出boolean的大小。在《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。

18.HashMap为什么不是线程安全的?

面试被问到这个问题时,第一想法是HashMap源码中又没有实现synchronized,当然不会是线程安全的,不像Vector和HashTable等都实现了synchronized都是线程安全的。不过这只是浅显的回答,原则上的问题没有答到。
具体可参考:
https://blog.csdn.net/qq_38905818/article/details/105655083?spm=1001.2014.3001.5501
首先HashMap是线程不安全的,其主要体现:
(1)在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失
(2)在jdk1.8中,在多线程环境下,会发生数据覆盖的情况

19.Mybatis中的一级缓存和二级缓存

(1)一级缓存
  Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Mabits默认开启一级缓存。 在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。 每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。 Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。 SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。

(2)二级缓存
  二级缓存是mapper级别的,Mybatis默认是没有开启二级缓存的。 第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放代该mapper对应的二级缓存区域。 第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。
在这里插入图片描述

20.Mybatis的二级缓存如何开启?

首先在全局配置文件 mybatis-configuration.xml 文件中加入如下代码:

<!--开启二级缓存  -->
<settings>    
<setting name="cacheEnabled" value="true"/>
</settings>

其次在 UserMapper.xml 文件中开启缓存

<!-- 开启二级缓存 -->
<cache></cache>

我们可以看到 mapper.xml 文件中就这么一个空标签,其实这里可以配置,PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存。

<cache type="org.apache.ibatis.cache.impl.PerpetualCache"></cache>

专门针对SQL语句的二级缓存配置:
mybatis中还可以配置userCache和flushCache等配置项,userCache是用来设置是否禁用二级缓存的,在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

<select id="selectUserByUserId" useCache="false" resultType="com.ys.twocache.User" parameterType="int">    
select * from user where id=#{id}
</select>

这种情况是针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存,直接从数据库中获取。
  在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
  设置statement配置中的flushCache=”true” 属性,默认情况下为true,即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。

<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.ys.twocache.User" parameterType="int">    
select * from user where id=#{id}
</select>

一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。所以我们不用设置,默认即可。

21.JDK中默认的泛型表示?

JDK为了便于理解,用? 表示不确定的类型,一般用在通配K表示键V表示值T表示type类型E表示enum枚举。其实这四个都只是符号,都是表示泛型名称。换成其他字母都没关系,但是都要在之前声明。
借用https://blog.csdn.net/cris001cris/article/details/53712189中的一个实例如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

//虽然Test<T1,T2>,但类名字仍为Test。T1,T2只是告诉我们new的时候要加入泛型,更方便通用
//T1,T2可以任意定义,比如改成K,V都可以
//他们不会关联到其他类,只是在本类中通用
public class Test<T1, T2> {
    public static void main(String[] args) {
        System.out.println(new Test().getT1());
        System.out.println(new Test().getT2());
        new Test<String, String>().getClassName("");//T1,T2在new的时候用到,这里都为String
        new Test().getClassAndList(Integer.class);
        //HashMap的括号里面不能是T,E,T1,T2等不确定的东西,但可以是?
        HashMap<?, ?> map = new HashMap<Object, String>();
        List<?> list = new ArrayList<String>();
    }

    public T1 getT1() {
        //这里的“T1”替换成1或1.0都会报错
        return (T1) "T1";

    }

    T2 getT2() {
        //将自动转型为String
        return (T2) "T2";

    }

    public <T> void getClassName(T x) {
        //<T>必须放在void或者返回类型的前面
        System.out.println(x.getClass().getName());
    }

    public <T> Class<?> getClassAndList(Class<?> a) {
        //Class<T>前面缺少<T>必须定义,否则将出现编译错误
        //T改成其他字母都可以,但一定要声明
        // 返回类型和参数中的类型:Class<T>和Class<?>都可以。因为返回的a的类型为Class<T>,Class<?>可以通配
        //当两个都是Class<?>,参数中的?自动通配成T
        System.out.println(a.getClass().getName());//传入的a是一个类,Class类型
        //参数里面的Class<T>最大的好处是如果方法里面定义了泛型,可以自动获取类型值,比如如下的List<T>可以自动获取到a的类型,不必强调死
        List<?> aa = new ArrayList<T>();
        //List<?> aa = new ArrayList<?>();会报错,以为ArrayList必须是一种类型,List<>起到通配的作用
        //List<T> aa = new ArrayList<T>();当然正确
        System.out.println(aa);
        return a;
    }
}

22.equals()和equalsIgnoreCase()的区别?

equals()区分大小写;
equalsIgnoreCase()不区分大小写。
实例:

String a="ABC";
a.equals("abc");//false
a.equalsIgnoreCase("abc");//true

23.CLI和GUI?

(1)CLI
命令行界面(英语:command-line interface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。也有人称之为字符用户界面(CUI)。
(1)GUI
图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。

24.通信模式中的同步与异步,阻塞和非阻塞?

(1)同步、异步
概念:消息的通知机制
解释:涉及到IO通知机制;
所谓同步,就是发起调用后,被调用者处理消息,必须等处理完才直接返回结果,没处理完之前是不返回的,调用者主动等待结果;
所谓异步,就是发起调用后,被调用者直接返回,但是并没有返回结果,等处理完消息后,通过状态、通知或者回调函数来通知调用者,调用者被动接收结果。

(2)阻塞、非阻塞(相对数据而言)
概念:程序等待调用结果时的状态。进程访问数据的时候,数据是否就绪的一种处理状态。
解释:涉及到CPU线程调度;
所谓阻塞,就是调用结果返回之前,该执行线程会被挂起,不释放CPU执行权,线程不能做其它事情,只能等待,只有等到调用结果返回了,才能接着往下执行;
所谓非阻塞,就是在没有获取调用结果时,不是一直等待。

25.Windows中查看JDK安装位置?

java -verbose

26.switch() case…中的switch后面能用哪些数据类型?

答案:int、char、byte、short、枚举、String(对JDK版本有要求,必须为1.7及以上版本)
解析:
(1)swtich()里面必须是int和enum
(2)short、char或者byte他会自动转换为int的。
(3)long不能自动转换为int,因为long比int范围大,可能会丢失精度。
(4)java把string也’转化’成int了,用string的hash值(int型,hashCode()的返回值)代替string进行switch,然后再对string做一遍equals()判断

27.Java中instanceof关键字与isAssignableFrom()方法对比?

isAssignableFrom()方法是从类继承的角度去判断,instanceof关键字是从实例继承的角度去判断。
isAssignableFrom()方法是判断是否为某个类的父类,instanceof关键字是判断是否某个类的子类

(1)isAssignableFrom()方法
Class.isAssignableFrom()是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的子类或接口
格式为:

Class1.isAssignableFrom(Class2) 

调用者和参数都是java.lang.Class类型

(2)instanceof关键字
instanceof关键字用来判断一个对象实例是否是一个类或接口的或其子类子接口的实例
格式是:

obj instanceof TypeName  

第一个参数是对象实例名,第二个参数是具体的类名或接口名,例如 String,InputStream。其返回值为boolean。

实例(转自(http://sunnylocus.iteye.com/blog/555676)):

package com.bill99.pattern;

public class AssignableTest {
    
    public AssignableTest(String name) {
    }
    /**
     * 判断一个类是否是另一个类的父类
     * 是打印true
     * 否打印false
     */
    public static void testIsAssignedFrom1() {
        System.out.println("String是Object的父类:"+String.class.isAssignableFrom(Object.class));//false
    }
    /**
     * 判断一个类是否是另一个类的父类
     * 是打印true
     * 否打印false
     */
    public static void testIsAssignedFrom2() {
        System.out.println("Object是String的父类:"+Object.class.isAssignableFrom(String.class));//true
    }
    /**
     * 判断一个类是否和另一个类相同
     * 是打印true
     * 否打印false
     */
    public static void testIsAssignedFrom3() {
        System.out.println("Object和Object相同:"+Object.class.isAssignableFrom(Object.class));//true
    }

    /**
     * 判断str是否是Object类的实例
     * 是打印true
     * 否打印false
     */
    public static void testInstanceOf1() {
        String str = new String();
        System.out.print("str是Object的实例:");
        System.out.println(str instanceof Object);//true
    }
    /**
     * 判断o是否是Object类的实例
     * 是打印true
     * 否打印false
     */
    public static void testInstanceOf2() {
        Object o = new Object();
        System.out.print("o是Object的实例:");
        System.out.println(o instanceof Object);//true
    }
    
    public static void main(String[] args) {
        testIsAssignedFrom1();
        testIsAssignedFrom2();
        testIsAssignedFrom3();
        testInstanceOf1();
        testInstanceOf2();
    }
}

结果:
StringObject的父类:false
ObjectString的父类:true
ObjectObject相同:true
str是Object的实例:true
o是Object的实例:true

28.instanceof关键字与isInstance()对比?

instanceof关键字与isInstance()都是用来判断对象的类型的,但是当需要动态地判断对象的类型时instanceof就无能为力了,而isInstance()方法却能发挥作用。
(1)instanceof
instanceof是Java中的操作符,其作用是该操作符判断左边的对象是否是它右边类的实例,返回值boolean类型。
(2)isInstance()
isInstance()是Class类的一个方法public boolean isInstance(Object obj)
该方法的作用是在run time判断指定的obj对象是否是当前Class实例所代表的类的实例。
官方解释
Determines if the specified Object is assignment-compatible with the object represented by this Class. This method is the dynamic equivalent of the Java language instanceof operator.
大致意思如下:
确定指定的对象是否与该类表示的对象赋值兼容。该方法是Java语言的instanceof操作符的动态等效方法。

29.SIT测试和UAT测试?

(1)SIT,英文System Integration Testing的简称,系统集成测试,也叫做集成测试,是软件测试的一个术语,在其中单独的软件模块被合并和作为一个组测试。它在单元测试以后和在系统测试之前。集成测试在已经被单元测试检验后进行作为它的输入模式,组织它们在更大的集合,和递送,作为它的输出,集成系统为系统测试做准备。集成测试的目的是校验功能、性能和可靠性要求,配置在主设计项目中
(2)UAT,英文User Acceptance Test的简写,也就是用户验收测试,或用户可接受测试,系统开发生命周期方法论的一个阶段,这时相关的用户或独立测试人员根据测试计划和结果对系统进行测试和接收。是面向最终用户的测试,结束之后通常就可以发布生产环境了。它让系统用户决定接收系统,它是一项确定产品能够满足合同或用户所规定需求的测试,这是管理性和防御性控制。
区别与联系:
SIT是集成测试
UAT是验收测试
时间上看,UAT要在SIT后面,UAT测试要在系统测试完成后才开始。
测试人员看,SIT由公司的测试员来测试,而UAT一般是由用户来测试。它们两个之间的专注点是不一样的。UAT主要是从用户层面这些去考虑和着手测试,而SIT主要是系统的各个模块的集成测试。这在整个软件过程理论的基础知识中相当重要的。理论上讲SIT是由专业的测试人员去完成,UAT是由用户去做的。
如果按照规范来的话,做UAT测试的人一定是要对业务很精通的,并且是具有代表性的用户,关注的东西就是业务流程是否通畅是否符合业务的需要。以需求分析文档为重要参考,还有一些用户的操作习惯等等一系列的东西。

30.Windows中的cmd命令行窗口命令是什么语言?

准确的说cmd并不是某一种语言,无论是WINDOWS系统,百还是LINUX 系统,每种系统都有着各自的图形窗口状态,而命令行状态只是操作系统下的一种状态。这种状态(cmd命令)可以是由C语言编写的、也可以是由汇编语言编写的。

31.Java中的类为什么不能多继承?

父类方法有方法体,也就是说能实现功能,子类继承父类,没有重写方法,调用的是父类的功能;假如可以继承多个父类,那么当父类A,B中有同样的方法或参数时,子类C调用父类方法或属性时很难判断要调用谁;因此要限制单继承;
但是接口不同,接口没有方法体,也就是没有功能,功能是实现类来做的,因此不用考虑让谁做的问题;定义的属性也是常量,要通过接口名来调用;

32.JDK1.7后的try-catch处理文件流?

格式
try (
流对象的创建
) {
流对象的使用
}
try 后面的小括号中,表示不管 try 块是正常结束还是异常结束,这个资源都会被自动关闭。

实例

		try(
				FileInputStream fis = new FileInputStream("d:/IO文档/aaa.txt");
				FileOutputStream fos = new FileOutputStream("d:/IO文档/bbb.txt");
		){
			
			byte[] bs = new byte[1024];
			int len = 0;
			while((len = fis.read(bs)) != -1) {
				fos.write(bs, 0, len);
			}
			
		}

33.Java的泛型采用擦除法实现?怎么理解泛型擦除?

34.Java中static(静态变量/方法)的优缺点?

Static关键字声明的变量或方法称为静态变量/方法;
静态static变量/方法在类加载的过程中被初始化,而且在内存中只存在一份,所有可以把它当作是全局变量/方法;

1.优点:
(1)属于类级别的,所有不需要创建对象就可以直接使用;
(2)全局唯一,内存中唯一,静态变量可以唯一标识某些状态;
(3)初始化在类加载时候,常驻在内存中,调用快捷方便(绝对比你创建一个类后再调用它的非静态方法方便吧!);

用处:
(1)静态方法最适合工具类中方法的定义;比如文件操作,日期处理方法等;
(2)静态方法适合入口方法的定义;比如单例模式,因为从外部拿不到构造函数,所有定义一个静态的方法获取对象非常有必要;
(3)静态变量适合全局变量的定义;(这个用途很广呀,比如常用一个布尔型静态成员变量做控制符)

2.缺点:
静态方法/变量属于类级别的,意味着不需要创建对象就可以使用,因此有下面缺点:
(1)静态方法不能调用非静态的方法和变量;(非静态方法可以任意的调用静态方法/变量)
(2)不能使用this和super关键字(很明显,它属于类级别滴,没有创建对象签怎么可以用this/super)

35.构造函数私有化的作用?

构造函数私有化的类的设计保证了其他类不能从这个类派生或者创建类的实例
此外,还有这样的用途:
  例如,实现这样一个class,它在内存中至多存在一个,或者指定数量个的对象(可以在class的私有域中添加一个static类型的计数器,它的初值置为0,然后在GetInstance()中作些限制,每次调用它时先检查计数器的值是否已经达到对象个数的上限值,如果是则产生错误,否则才new出新的对象,同时将计数器的值增1)。最后,为了避免值复制时产生新的对象副本,除了将构造函数置为私有外,复制构造函数也要特别声明并置为私有。
如果将构造函数设计成Protected,也可以实现同样的目的,但是可以被继承。

如果外部还想使用含有私有构造函数的类的实例怎么办?

public class Person{
    private String name;
    Private Person newPerson; //Person类唯一的实例化对象
    Private PersonString Name{  //私有的构造方法
        this.name = name;
    }
    newperson = new Person("百度知道");
    Public Person getInstance(){  //将newperson返回给外部调用处!!!
        return newperson;
    }
}

36.git fetch和git pull的区别?

git pull看起来像git fetch+get merge,但是根据commit ID来看的话,他们实际的实现原理是不一样的。
可参考:
https://blog.csdn.net/weixin_41975655/article/details/82887273

37.主线程、守护线程、非守护线程的区别与联系?

(1)主线程
main方法,但不是守护线程。
(2)守护线程
指在程序运行的时候在后台提供一种通用服务的线程,如gc。
(3)非守护线程
也叫用户线程,由用户创建。
(4)关系:
主线程和守护线程一起销毁;
主线程和非守护线程互不影响。

38.序列化和反序列化的原理?

其实分别就是通过ObjectOutputStream.writeObject()和ObjectInputStream.readObject()来实现的。
序列化相关问题可参考我的另一篇文章:《Java中的序列化(Serializable)相关问题》

39.CS和BS?

1、概念和特点
(1)CS(Client/Server 客户端-服务器):
  C/S结构在技术上很成熟,它的主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。因为客户端要负责绝大多数的业务逻辑和UI展示,又称为胖客户端。它充分利用两端硬件,将任务分配到Client 和Server两端,降低了系统的通讯开销。C/S结构的软件需要针对不同的操作系统系统开发不同版本的软件,加之产品的更新换代十分快,已经很难适应百台电脑以上局域网用户同时使用。
  C/S 架构是一种典型的两层架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信。
(2)BS(Browser/Server 浏览器-服务器):
  BS是目前应用系统的发展方向。BS是伴随着Internet技术的兴起,对C/S架构的改进,为了区别于传统的C/S 模式,特意称为B/S模式。在这种结构下,通过W3浏览器来进入工作界面,极少部分事务逻辑在前端(Browser)实现,主要事务逻辑在服务器端(Server)实现,形成三层(3-tier)结构。这样使得客户端电脑负荷大大简化(因此被称为瘦客户端),减轻了系统维护、升级的支出成本,降低了用户的总体成本(TCO)。
  BS的主要特点是分布性强、维护方便、开发简单且共享性强、总体拥有成本低。但数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低,难以实现传统模式下的特殊功能要求。它是瘦客户端,对大量的数据输入以及报表的应答等都需要通过浏览器与服务器进行交互,通信开销大,而且对于实现复杂的应用构造有较大的困难。
  
2、系统结构图(摘自网络)
在这里插入图片描述
在这里插入图片描述

3、对比

对象硬件环境客户端要 求软件安装升级和维护安全性
C/S用户固定,并且处于相同区域,要求拥有相同的操作系统。客户端的计算机电脑配置要求较高。每一个客户端都必须安装和配置软件。C/S每一个客户端都要升级程序。可以采用自动升级。一般面向相对固定的用户群,程序更加注重流程,它可以对权限进行多层次校验,提供了更安全的存取模式,对信息安全的控制能力很强。一般高度机密的信息系统采用C/S结构适宜。
B/S要有操作系统和浏览器,与操作系统平台无关。客户端的计算机电脑配置要求较低。可以在任何地方进行操作而不用安装任何专门的软件。不必安装及维护

40.集合和数组之间的互相转换?

1.集合转数组

2.数组转集合
https://blog.csdn.net/desperado0726/article/details/105021424?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-0&spm=1001.2101.3001.4242

41.流与集合之间的转换?

42.JVM编译的三种模式?

(1)解释模式(interpreted mode):源程序输入到计算机后,解释程序将程序逐句翻译,翻译一句执行一句边翻译边执行。
(2)编译模式(compiled mode):把源程序全部翻译成目标代码后才运行目标代码。
(3)混合模式(mixed mode):将解释模式和变异模式进行混合使用,有JVM自己决定,这是JVM的默认模式,也是推荐模式。
对应的Java非标准参数(java -X):
-Xint参数:在解释模式(interpreted mode)下,-Xint标记会强制JVM执行所有的字节码,jvm不会把代码全部编译完再运行而是一边编译一边运行,这当然会降低运行速度,通常低10倍或更多。
-Xcomp参数:在编译模式(compiled mode)下,-Xcomp参数与-Xint正好相反,JVM在第一次使用时会把所有的字节码编译成本地代码,把代码一次性编译完了才运行,从而带来最大程度的优化。
-Xmixed参数:-Xmixed是混合模式(mixed mode),将解释模式和变异模式进行混合使用,有JVM自己决定,这是JVM的默认模式,也是推荐模式

43.Arrays.asList和Lists.newList使用时的陷阱??

基本类型int不是对象类型,在使用Arrays.asList时,做泛型擦除时,将int[]当做对象类型,所以转成一个只有一个元素的List。在使用Arrays.asList转成的List时同样要注意,Arrays.asList返回类型为Arrays类内部定义的私有类ArrayList,并且继承与AbstractList,翻阅AbstractList源码是可以发现,是不支持add和remove操作的,也就是说Arrays.asList返回的List是个固定大小的List
如果希望转过后的list可以支持add和remove操作,可使用如下方法:

/*方法一*/
ArrayList<Integer> copyArrays=new ArrayList<>(Arrays.asList(integerArray));
 
/*方法二*/
List<Integer> integerList = new ArrayList<>();
Collections.addAll(integerList, integerArray);

如果想把一个基本类型数组转化为List,可使用如下方法:

Arrays.asList(ArrayUtils.toObject(intArray));

在使用com.google.common.collect提供的jar包Lists类Lists.newArrayList方法时,有相同的问题,如果传入基本类型数组,也无法转化成一个正常的List,这一点跟ArrayList结果是一致的。但是对象数组进行转化时,有一点不同,转成的List是支持add和remove操作的。

44.链表头插法和尾插法的对比?

1、头插法
(1)插入速度快(不需要遍历旧链表)
(2)头结点每次插入都会变化,头结点永远是最新的元素
(3)遍历时是按照插入相反的顺序进行
(4)由于头结点不断在变化,所以需要额外的维护头结点的引用,否则找不到头结点,链表就废了
2、尾插法
(1)插入速度慢(需要遍历旧链表到最后一个元素)
(2)头结点永远固定不变
(3)遍历时是按照插入相同的顺序进行

以梦为马,以汗为泉,不忘初心,不负韶华

梧高凤必至,花香蝶自来

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值