面试题小记
1、谈谈你对java的理解
java首先是一种面向对象的语言,然后面向对象编程有三个特征:封装、继承、多态、泛型;还有在java8的新特性lambda表达式等
其次呢,java支持跨平台性,一次编译处处运行
继承的好处:提高代码的复用性
注意:java中是单继承的,一个类只能继承一个直接父类,如果子类和父类中出现了同名的成员变量的时候,子类会优先访问自己对象中的成员变量,如果此时想要访问父类中的成员变量,我们可以使用super关键字来解决
super代表的是父类对象的引用,this代表的是当前对象的引用
重载:重载发生在同一个类中,在该类中如果存在多个同名方法,但是方法的参数类型,个数,顺序不一样,那么说明该方法被重载了
重写:重写发生在子类继承父类的关系中,父类中的方法被子类继承,方法名,返回值类型,参数完全不一样,但是方法体不一样,那么说明父类中的该方法被子类重写了
2、java中的反射
1)反射机制其实就是指程序在运行的时候能够获取自身的信息。如果知道一个类的名称或者它的一个实例对象,那么就能把这个类的所有方法和变量的信息(方法名、变量名、方法、修饰符、类型、方法参数等等所有信息)
找出来。如果明确知道这个类里的某个方法名+参数个数类型,还能通过传递参数来运行那个类里的那个方法
2)当然在平时的编程中,反射基本使用不到,但是在编写框架的时候,反射用的就比较多了,比如我们要使用某一个类型进行操作,但是这个类是通过配置文件配置进来的,那么我们就需要先读取配置文件,然后拿到这个类的全类
名,然后利用反射API来完成相应的操作
3、开发中哪里使用到反射了
反射是在框架中开发时才使用到的,比如使用JDBC连接数据库的时候,使用Class.forName(驱动类名),就是通过反射来加载数据库的驱动类,还有就是Spring框架中的IOC(动态加载管理Bean对象)创建对象以及AOP(动态代理)使用反
射进行底层实现。还有就是mybatis中Mapper接口代理对象的创建,也是通过反射来实现的
4、java中的内部类
1)定义在内部的,就是内部类。可以定义在方法的内部,也可以定义在类的内部
2)根据定义的位置不同可以分为
成员内部类:
普通成员内部类:
(1)定义在成员位置的内部类,就是成员内部类
(2)定义格式:
class 内部类类名{
内部类成员;
}
(3)成员内部类的说明:
内部类可以直接访问外部类的成员,包括私有成员
外部类访问内部类的成员,必须先创建内部类对象:
在外部类以外,创建访问内部类对象的格式
①外部类类名.内部类类名 内部类对象名称 = new 外部类类名().new 内部类类名();
私有的成员内部类的说明:
也就是一个成员内部类,在成员内部类的基础上加上了private关键字在外部类以外,不能直接访问外部类中私有的成员内部类,可以在外部类中定义一访问私有成员内部类中的方法,让外界可以调用公有的方法间接的
访问外部类中的私有成员内部类
静态的成员内部类:
也是一个成员内部类,在成员内部类的前面加上一个static关键字,静态成员内部类是外部类的静态成员,所以可以通过外部类名.内部类名的方式直接访问,而不需要创建外部类对象
静态内部类中的非静态成员,需要将所在的内部类对象创建出来之后,才能调用
静态成员内部类的对象创建格式:外部类类名.内部类类名 变量名 = new 外部类类名.内部类类名();
总结:一个是否需要创建对象,不取决于该类本身是否需要创建,而取决于访问的成员是否为静态的
局部内部类:
有名字的内部类:
定义在方法中的内部类,方法中的局部变量,外界都没有办法进行访问到,所以,方法中的内部类,外界也没有办法访问,可以在方法内部,创建局部内部类对象,调用对象的方法
外界调用局部类所在的方法,间接的创建局部内部类的对象,间接的访问到内部类的方法
匿名内部类:
没有名字的内部类
匿名内部类的使用前提:继承一个类,实现一个接口
格式:
new 父类类名或接口名(){
父类方法的重写或者接口内容的实现;
}
匿名内部类本质:创建一个类的子类对象,接口的实现类对象
内部类名称总结:①如果是有名字的内部类,类名[外部类名$内部类名]
②如果是没有名字的内部类,通过匿名内部类的顺序描述类名,第一个匿名内部类的名称[外部类名$1],第二个匿名内部类的名称[外部类名$2]
5、java中几种常用的线程池
我们可以使用Java.util.concurrent(JUC)包下的Executors工具类,来帮我们创建java给我们提供的几种默认的线程池:
① newCacheTreadPool
创建一个可以缓存的线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,没回收的话就新建线程
总结: 线程池的最大核心线程为无限大,当执行第二个任务时第一个任务已经完成,则会复用执行第一个任务的线程;如果第一个线程任务还没有完成则会新建一个线程。
② newFixedThread
创建一个定长的线程池,可控制最大并发数,超出的线程进行队列等待。
总结:创建指定长度的线程池,任务超出当前线程池执行线程数量则会一直等待,直到运行。
③ newScheduleThreadPool
可以创建定长的、支持定时任务,周期任务执行。
总结:以下案例中延迟2秒后开始执行线程池中的所有任务。
④ newSingleExecutor
创建一个单线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
⑤ 自定义线程池
通过 new ThreadPoolExecutor() 的写法创建线程池,这样写线程数量更灵活,开发中多数用这个类创建线程。
关于线程池中参数的配置:
对于线程池的配置,不同的业务场景,不同的服务器我们的配置是不一样的,像我之前用的多线程批量导出报表功能,这种任务属于IO密集型的,它本身由于IO阻塞导致程序运行速度比较慢,所以我多配置了一些线程
由于我们的服务器 是16核的,我们要尽可能充分利用CPU,所以我们的核心线程数配置了64个,最大线程我们配置了128个,另外等待队列我们配置的很少,因为本身IO阻塞就慢,所以我们就尽量不让过多的线程再进
入阻塞队列中了
还有,像我之前用到了线程池xxxx,那种情况属于CPU高速运行的情况我们也叫CPU密集型,对于这种情况,所以我们线程不能配置太多,因为上下文切换也会影响CPU的 运行速度,所以我们配置的核心线程数和我们
的CPU核心数(16)保持一致,最大线程数我们配置了32个,我们队列就会多配置一些,比如64个,也能配置太多,配置太多的话会造成线程阻塞,如果任务处理还是运算不够的话,可以使用负载均衡来多配置几份项目
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了