以下时准备实习面试时整理的面试题第二部分,大家慢慢消化,第一部分也可点[面试题整理及凉经分享],收藏再看,不要收藏吃灰哟!(https://blog.csdn.net/qq_41570843/article/details/108019015)
ArrayList为什么是线程不安全
public class ContainerNoSafeDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 1; i <= 3 ; i++) {
new Thread(() ->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
HashSet为什么是线程不安全
public class ContainerNoSafeDemo {
public static void main(String[] args) {
Set<String> set = new CopyOnWriteArraySet<>(); //Collections.synchronizedSet(new HashSet<>()) ;
for (int i = 1; i <= 30 ; i++) {
new Thread(() ->{
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
HashMap为什么线程不安全
public class ContainerNoSafeDemo {
public static void main(String[] args) {
Map<String,String> map = new ConcurrentHashMap<>(); //Collections.synchronizedMap(new HashMap<>()) ;
for (int i = 1; i <= 30 ; i++) {
new Thread(() ->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
jvm方法作用域内存指针指向地址的基本功
公平锁和非公平锁
可重入锁(递归锁)
自旋锁
独占锁、共享锁
1、数据存放位置不同:
cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、安全程度不同:
cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3、性能使用程度不同:
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
4、数据存储大小不同:
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储与服务端,浏览器对其没有限制。
封装
封装是将描述某类事物的数据与处理这些数据的函数封装在一起,形成一个有机整体,称为类。类所具有的的封装性可使程序模块具有良好的独立性与可维护性。
类中的私有数据在类的外部不能直接使用,外部只能通过类的公共接口方法(函数)来处理类中的数据,从而保证数据的安全。封装的目的是增强安全性和简化编程,仅需要通过外部接口,特定的访问权限来使用类的成员。
类设计好以后,就可以实例化该对象。对象形成时,也界定了对象与外界的内外界限。对象的属性,行为等实现的细节则被封装在对象的内部。
用鸡蛋来比拟对象,属性好比蛋黄,隐藏于中心,不能直接接触,代表对象的状态
行为好比蛋白,可以经由接口与外界交互而改变对象的属性值,并把这种改变通过接口呈现出来。
接口好比蛋壳,它可以与外界直接接触。外部也只能通过公开的接口方法来改变对象内部的属性值,从而使类中数据的安全性得以保证。
在Java中,类是基本的封装单元,基于面向对象思想编程的基础,可以把具有相同业务性质的代码,封装在一个类里,然后通过共有接口方法,向外部提供服务,同时向外部屏蔽类中的具体实现方式。
继承
继承是面向对象程序设计中软件复用的关键技术,通过继承,可以进一步扩充新的特性,适应新的需求。这种可复用,可扩充技术在很大程度上降低了大型软件的开发效率。
继承的目的在实现代码重用
继承能以原有类为基础,派生新的类。
Java中的继承
继承可以简化类的定义,扩展类的功能。但是java中只允许单继承和多层继承,不支持多继承。 不能一个类继承多个类。
Java继承只能显示继承父类所有的公有属性及公有方法,隐含的继承了私有属性。
继承的限制
Java中不允许多重继承,但是允许多层继承
从父类继承的私有成员,不能被子类直接使用。
子类继承父类时,对于其所有的私有成员采用隐式继承,子类无法直接操作这些私有属性,必须通过设置set()和get()方法简介操作。
子类在进行对象实例化时,从父类继承来的数据成员需要先经过父类的构造方法来进行初始化,然后再用子类的构造方法来初始化本地的数据成员。
被final修饰的方法不能被子类覆盖写实例,被final修饰的类不再被继承。
多态
多态的基本概念:字面意思就是一种类型多种状态。
方法多态性,体现在方法的重载与覆写上
方法重载 指同一个方法名称,根据其传入的参数类型,个数,和顺序的不同,所调用的方法体也不同,即一个方法名称在一个类中由不同的功能实现。
方法覆写 指父类中的一个方法名称,在不同的子类由不同的功能实现,而后依据实例化子类的不同,同一个方法,可以完成不同的功能
对象多态性,体现在父,子对象之间的转型上
多态性允许将父对象设置成与一个或更多的子对象相等的技术,通过赋值之后,父对象就可以根据当前被复制的不同子对象,以子对象的特性加以运作。多态意味着相同的父类信息,发送给不同的子对象,子对象表现出的形态不同。
多态中的一个核心概念就是:子类(派生类)对象可以视为父类(基类)对象。
方法多态性
方法的重载体现了方法的多态性
对象多态性
向上转型父类对象通过子类对象去实例化,实际上就是对象的向上转型。向上转型不需要进行强制类型转换,但是会丢失精度。
向下转型父类的对象可以转换为子类对象,必须进行强制的类型转换。
(此题为高频题,一定要掌握并进行详细了解,以及jvm的知识块)
◆寄存器:我们在程序中无法控制
◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
◆堆:存放用new产生的数据
◆静态域:存放在对象中用static定义的静态成员
◆常量池:存放常量
◆非RAM存储:硬盘等永久存储空间
总结
栈中用来存放一些原始数据类型的局部变量数据和对象的引用(String,数组.对象等等)但不存放对象内容
堆中存放使用new关键字创建的对象.
字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。
(依赖注入,把Javabean放入sping的IOC容器中进行统一管理)
有两种方法
a.在要加入容器的bean上加@component
并指定扫描该类所在的包
b.在配置类中使用@bean进行注册
(IOC和AOP也是spring必问题之一)
.beans 包和 org.springframework.context 包构成了Spring 框架 IoC 容器的基础。
.BeanFactory 是 Spring IoC 容器的具体实现,用来包装和管理前面提到的各种 bean。BeanFactory 接口是 Spring IoC 容器的核心接口。
面向切面编程,在我们的应用中,经常需要做一些事情,但是这些事情与核心业务无关,比如,要记录所有 update方法的执行时间时间,操作人等等信息,记录到日志, 通过 spring 的 AOP 技术,就可以在不修改 update的代码的情况下完成该需求。
特点
1、枚举实例必须在 enum
关键字声明的类中显式的指定(首行开始的以第一个分号结束)
2、除了1, 没有任何方式(new,clone,反射,序列化)可以手动创建枚举实例
3、枚举类不可被继承
4、枚举类是线程安全的
5、枚举类型是类型安全的(typesafe)
6、无法继承其他类(已经默认继承Enum)
从Color
类中可以看出, Color对象是在静态域创建,由类加载时初始化,JVM保证线程安全,这样就能确保Color对象不会因为并发同时请求而错误的创建多个实例.
2.对序列化进行特殊处理,防止反序列化时创建新的对象
我们知道一旦实现了Serializable接口之后,反序列化时每次调用 readObject()方法返回的都是一个新创建出来的对象.
而枚举则不同,在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过Enum的valueOf()
方法来根据名字查找枚举对象。
3.私有构造函数, 无法正常的 new
出对象
4.无法通过 clone()
方法,克隆对象
5.无法通过反射的方式创建枚举对象
枚举的使用
如上诉 Color
枚举类,就是典型的枚举常量.
它可以在 switch
语句中使用
枚举类型是类型安全的,可以对传入的值进行类型检查:
如有个 handleColor(Color color)
方法,那么方法参数自动会对类型进行检查,只能传入 Color.WHITE
和Color.BLACK
,如果使用 static final
定义的常量则不具备 类型安全的特点.
枚举类可以编写自己的构造函数,但是不能声明public,protected
,为了是不让外部创建实例对象,默认为private
且只能为它.
除了枚举常量外, enum是一个完整的类,它也可以编写自己的构造方法以及方法,甚至实现接口.
这里需要注意,枚举类不能继承其他类,因为在编译时它已经继承了 Enum
,java无法多继承
枚举与单例模式
单例模式网上有6-7中写法,除了 枚举方式外, 都有两个致命的缺点, 不能完全保证单例在jvm中保持唯一性.
解决方案 : 在构造上述中判断,当多于一个实例时,再调用构造函数,直接报错.
解决方案 : 使用readResolve()方法来避免此事发生.
这两种缺点虽然都有方式解决,但是不免有些繁琐.
枚举类天生有这些特性.而且实现单例相当简单.
public enum Singleton {
INSTANCE;
public void method() {
// todo ...
}
}
所以,枚举实现的单例,可以说是最完美和简洁的单例了.推荐大家使用这种方式创建单例.
但是,枚举类的装载和初始化时会有时间和空间的成本. 它的实现比其他方式需要更多的内存空间,所以在Android这种受资源约束的设备中尽量避免使用枚举单例,而选择
双重检查锁(DCL)
和静态内部类
的方式实现单例.
枚举与策略模式
特定的常量类型与主体中的方法或行为有关时,即当数据与行为之间有关联时,可以考虑使用枚举来实现策略模式.
1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦
2.可以使用容易提供的众多服务,如事务管理,消息服务等
3.容器提供单例模式支持
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
5.容器提供了众多的辅助类,能加快应用的开发
6.spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等
7.spring属于低侵入式设计,代码的污染极低 8.独立于各种应用服务器
9.spring的DI机制降低了业务对象替换的复杂性
10.Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring的部分或全部
(高频必问,关于springmvc知识点的高频题)
客户端发送请求之后,会被前端控制器(DispatcherServlet)拦截,之后前端控制器会调用处理器映射器(HandlerMapping),将去类中找该方法,找到之后会给前端控制器返回一个执行链,前端控制器通过处理器适配器(HandlerAdapter)去执行Handler,执行之后返回一个ModelAndView对象,再将该对象返回给前端控制器,前端控制器通过视图解析器(ViewResolver)返回一个View视图,最后前端控制器将View视图响应给客户端浏览器
1:启动工程时,系统加载web.xml
2:当用户输入一个请求时,请求被web.xml中被拦截,转到了springmvc.xml中进行处理
3:由于HandlerMapping有不同的实现类,所以map
4:HandlerMapping根据请求的url找到相应的Handler,返回给DispatcherServlet
5:DispactherServlet请求处理器适配器HandlerAdapter去执行Handler(常称为Controller)
6:处理器适配器(HandlerAdapter)执行Handler
7:Handler执行完毕后会返回给处理器适配器(HandlerAdapter)一个ModelAndView对象
8:HandlerAdapter接收到Handler返回的ModelAndView后,将其返回给前端控制器
9:DispatcherServlet接收到ModelAndView后,会请求视图解析器(View Resolver)对视图进行解析
10:View Resolver根据View信息匹配到相应的视图结果,反馈给DispatcherServlet
11:DispatcherServlet收到View具体的视图后,进行视图渲染,将Model中的数据模型填充到View视图中的request域,生成最终的视图View
12:DispatcherServlet向用户返回请求的结果
CountDownLatch:秦灭六国,统一华夏
CountDownLatch:
计数器,某个线程等待N个线程执行完毕后再继续执行,N就是对应的计数,每个执行完毕就减一,直到所有完成。可以看作是1个等多个。
常用方法:
public CountDownLatch(int count) { };
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,一直等待直到count值为0然后继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间timeout后,即使count值还没变为0的话也会继续执行
public void countDown() { }; //将count值减1
CyclicBarrier:收集七个龙珠,召唤神龙
CyclicBarrier:
循环计数器,一般是N个线程相互执行等待,所有执行完毕再继续下一步动作。可以看作是n个互相等待。
常用方法:
public CyclicBarrier(int parties, Runnable barrierAction) {} //barrierAction 回调函数
public CyclicBarrier(int parties) {}
//等待
public int await() throws InterruptedException, BrokenBarrierException { };
//等待一段时间
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };
CountdownLatch和CyclicBarrier的区别
1、CountDownLatch简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。
2、CyclicBarrier是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行!
3、CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
Semaphore:
信号量,一般是获取到信号量的执行某个动作,完毕后释放,其他继续获取。类似锁。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-60jIrPft-1597477935487)(第四天整理(7.16)].assets/image-20200718110024649.png)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FnNEy8pM-1597477935487)(第四天整理(7.16)].assets/image-20200718111557602.png)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ucz6zKGe-1597477935488)(第四天整理(7.16)].assets/image-20200718112754089.png)
spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc。spring mvc 是只是spring 处理web层请求的一个模块。
Spring 最重要的特征是依赖注入。所有 SpringModules 不是依赖注入就是 IOC 控制反转。
当我们恰当的使用 DI 或者是 IOC 的时候,我们可以开发松耦合应用。松耦合应用的单元测试可以很容易的进行。
Spring MVC 提供了一种分离式的方法来开发 Web 应用。通过运用像 DispatcherServelet,MoudlAndView 和 ViewResolver 等一些简单的概念,开发 Web 应用将会变的非常简单。
Spring 和 SpringMVC 的问题在于需要配置大量的参数。
Spring Boot 通过一个自动配置和启动的项来目解决这个问题。为了更快的构建产品就绪应用程序,Spring Boot 提供了一些非功能性特征。
环境配置
引入Shiro安全框架的依赖
拦截器配置
方法一:在web.xml中配置Shiro拦截器
创建Spring整合Shiro安全框架的配置文件applicationContext-shiro.xml
方法二:通过ShiroConfig类来配置
在ShiroConfig类中创建@Bean注解配置拦截器.
自定义Realm类
Realm能做的工作主要有以下几个方面:
getAuthenticationInfo方法:验证是否能登录,并返回验证信息
getAuthorizationInfo方法:验证是否有访问指定资源的权限,并返回所拥有的所有权限
supports方法:判断是否支持token(例如:HostAuthenticationToken,UsernamePasswordToken等)
注意:
自定义Realm类必须继承AuthorizingRealm类,并覆盖方法doGetAuthenticationInfo
Realm类配置
将自定义的Realm类注入到securityManager中.
方法一:在applicationContext-shiro.xml中配置
方法二:在ShiroConfig中通过@Bean注解配置
登录验证
编写登录接口:
权限验证
在自定义的Realm类中重写如下方法
其中这里的权限,是从数据库中读取的,数据库结构如下:
我们在使用mybatis时需要根据数据表创建pojo类,pojo类的映射文件以及sql语句和Dao层,而这些部分没有什么技术含量,myBatis官方提供了逆向功能,可以根据数据表自动生成pojo,映射文件以及dao层。我们通常将Dao层称为mapper.java,将映射文件称为mapper.xml,将会实体类称为pojo。
导入jar包
写配置文件 ,放在 main/resources 目录下
mybatis-generatorConfig.xml
3.编写java类,位置随意,我放 test/java 目录下
DAO (Data Access Objects 数据存取对象)可以在位于业务逻辑和持久化数据之间实现对持久化数据的访问,也就是数据访问层。在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。DAO模式分为了Data Accessor模式和Active Domain Object模式。Data Accessor模式负责封装了数据访问实现的机制,通过提供数据存取接口,实现数据访问和业务逻辑的分离。Active Domain Object模式主要是实现了业务数据的对象化封装。
过滤器可以动态地拦截请求和响应,然后可以进行一些权限判断,日志处理,参数替换以及接口跳转等逻辑;通过在web.xml中配置过滤器filter,并且自定义实现filter过滤器的过滤逻辑,可以实现对请求和响应的拦截。
Iterator提供了统一遍历操作集合元素的统一接口, Collection接口实现Iterable接口,
每个集合都通过实现Iterable接口中iterator()方法返回Iterator接口的实例, 然后对集合的元素进行迭代操作.
有一点需要注意的是:在迭代元素的时候不能通过集合的方法删除元素, 否则会抛出ConcurrentModificationException 异常. 但是可以通过Iterator接口中的remove()方法进行删除.
答:Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包括了可以返回迭代器实例的迭代方法。迭代器可以在迭代过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除
关于Iterator的简单的解释Iterator提供了同意遍历操作集合元素的统一接口,
static是表示静态的意思,它可用来修饰成员变量和成员函数,被静态修饰的成员函数只能访问静态成员,不能访问非静态成员。静态是随着类的加载而加载,因此可以直接用类进行访问。
覆盖又称为重写,重写就是子类中的方法和子类继承的父类中的方法一样(函数名、参数类型、参数、返回值类型),但子类的访问权限不要低于父类的访问权限。重写的前提是必须要继承,private修饰不支持继承,因此被私有的方法不能重写。静态的方法形式上是可以被重写的,即子类中可以重写父类中的静态方法,但实际上在内存的角度上静态方法是不可以被重写的。
垃圾回收使得Java程序员在编写程序的时候不再需要考虑内存管理,通过自动进行垃圾回收,在一定程度上防止内存泄露,提高内存的使用效率。垃圾回收的原理:通过一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
公平锁每次获取锁时都需要判断等待队列中是否还有排在前面的线程,若不存在才能继续获取锁,若队列还存在等待线程则获取失败,当前线程进入队列尾部;非公平锁是指被唤醒的线程在获的CPU之前,可能会被刚好准备入队列的其余线程占用CPU,被唤醒的线程得不到CPU而重新等待,也就是并不是一种先等待先执行的顺序。
如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,FIFO。对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁还需要判断当前节点是否有前驱节点,如果有,则表示有线程比当前线程更早请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。
C++虚类相当于java中的抽象类,与接口的不同处是:
1.一个子类只能继承一个抽象类(虚类),但能实现多个接口
2.一个抽象类可以有构造方法,接口没有构造方法
3.一个抽象类中的方法不一定是抽象方法,即其中的方法可以有实现(有方法体),接口中的方法都是抽象方法,不能有方法体,只有方法声明
4.一个抽象类可以是public、private、protected、default,接口只有public
5.一个抽象类中的方法可以是public、private、protected、default,接口中的方法只能是public和default修饰,实际上都是public的abstract方法
相同之处是:
都不能实例化。
补充:
接口是一类特殊的抽象类,是更抽象的抽象类,你可以这样理解。抽象类是一个不完整的类,接口只定义了一些功能。
HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地址,这样即便有相同含义的两个对象,比较也是不相等的。HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等的。若equals()不相等则认为他们不相等。如果只重写hashcode()不重写equals()方法,当比较equals()时只是看他们是否为同一对象(即进行内存地址的比较),所以必定要两个方法一起重写。HashMap用来判断key是否相等的方法,其实是调用了HashSet判断加入元素 是否相等。重载hashCode()是为了对同一个key,能得到相同的Hash Code,这样HashMap就可以定位到我们指定的key上。重载equals()是为了向HashMap表明当前对象和key上所保存的对象是相等的,这样我们才真正地获得了这个key所对应的这个键值对。
重写java object hashCode方法,是为了在一些算法中避免我们不想要的冲突和碰撞。比如其HashMap,HashSet的使用中。
重写了equals()方法,而你的对象可能会放入到散列(HashMap,HashTable或HashSet等)中,那么还必须重写hashCode(), 如果你的对象有可能放到有序队列(实现了Comparable)中,那么还需要重写compareTo()的方法。
1.& (1)按位运算符; (2)逻辑运算符
作为逻辑运算符时,&左右两端条件式有一个为假就会不成立,但是两端都会运行
2.&&——逻辑运算符
&&也叫做短路运算符,因为只要左端条件式为假直接不成立,不会去判断右端条件式。
相同点:只要有一端为假,则语句不成立
优点: 1、 减少了对数据库的读操作,数据库的压力降低 2、 加快了响应速度
缺点: 1、 因为内存断电就清空数据,存放到内存中的数据可能丢失
缓存主要是为了提高系统性能和处理高并发请求。当从数据库或者磁盘文件中读取速度较慢,并且结果不是易变的时候,将结果放入缓存,提高请求的响应速度;在高并发场景下,缓存的使用可以降低数据库等的压力。
持久层设计要考虑安全性问题、并发性能问题、数据库性能问题以及缓存设置问题,需要提供抽象化的数据访问接口来操作数据,并且具有可移植性等。我使用过的持久层框架包括Hibernate,MyBatis以及SpringData
IOC也叫控制反转,将对象间的依赖关系交给Spring容器,使用配置文件来创建所依赖的对象,由主动创建对象改为了被动方式,实现解耦合;DI(依赖注入),和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖IOC容器来动态注入对象需要的外部资源(对象等)。依赖注入DI的实现方式包括接口注入,Setter方法注入以及构造方法注入;
(线程池一定要有所了解呀)
一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
二、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
三、通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
②线程池的种类
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
线程有五个状态:new创建状态,Runnable就绪状态,Running运行状态,Dead消亡状态,Blocked阻塞状态。创建线程通过start方法进入就绪状态,获取cpu的执行权进入运行状态,失去cpu执行权会回到就绪状态,运行状态完成进入消亡状态,运行状态通过sleep方法和wait方法进入阻塞状态,休眠结束或者通过notify方法或者notifyAll方法释放锁进入就绪状态
如果不是静态内部类,完全可以。那没有什么限制!
在静态内部类下,不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员
1、什么是枚举?
我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
2、定义枚举类型
定义枚举类型需要使用enum关键字,
在定义枚举项时,多个枚举项之间使用逗号分隔,最后一个枚举项后需要给出分号!但如果枚举类中只有枚举项(没有构造器、方法、实例变量),那么可以省略分号!建议不要省略分号!
不能使用new来创建枚举类的对象,因为枚举类中的实例就是类中的枚举项,所以在类外只能使用类名.枚举项。
3、枚举与switch
枚举类型可以在switch中使用
注意,在switch中,不能使用枚举类名称,例如:“case Direction.FRONT:”这是错误的,因为编译器会根据switch中d的类型来判定每个枚举类型,在case中必须直接给出与d相同类型的枚举选项,而不能再有类型。
4、所有枚举类都是Enum的子类
所有枚举类都默认是Enum类的子类,无需我们使用extends来继承。这说明Enum中的方法所有枚举类都拥有。
int compareTo(E e):比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序,例如FRONT的下标为0,BEHIND下标为1,那么FRONT小于BEHIND;
boolean equals(Object o):比较两个枚举常量是否相等;
int hashCode():返回枚举常量的hashCode;
String name():返回枚举常量的名字;
int ordinal():返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0;
String toString():把枚举常量转换成字符串;
static T valueOf(Class enumType, String name):把字符串转换成枚举常量。
5、枚举类的构造器
枚举类也可以有构造器,构造器默认都是private修饰,而且只能是private。因为枚举类的实例不能让外界来创建!
enum Direction {
FRONT, BEHIND, LEFT, RIGHT;//[在枚举常量后面必须添加分号,因为在枚举常量后面还有其他成员时,分号是必须的。枚举常量必须在枚举类中所有成员的上方声明。]
Direction()//[枚举类的构造器不可以添加访问修饰符,枚举类的构造器默认是private的。但你自己不能添加private来修饰构造器。] {
System.out.println("hello");
}
}
其实创建枚举项就等同于调用本类的无参构造器,所以FRONT、BEHIND、LEFT、RIGHT四个枚举项等同于调用了四次无参构造器,所以你会看到四个hello输出。
6、枚举类可以有成员
其实枚举类和正常的类一样,可以有实例变量,实例方法,静态方法等等,只不过它的实例个数是有限的,不能再创建实例而已。
7、枚举类中还可以有抽象方法
还可以在枚举类中给出抽象方法,然后在创建每个枚举项时使用“特殊”的语法来重复抽象方法。所谓“特殊”语法就是匿名内部类!也就是说每个枚举项都是一个匿名类的子类对象!
8、每个枚举类都有两个特殊方法
每个枚举类都有两个不用声明就可以调用的static方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方,下面是Direction类的特殊方法。
多线程不能用if,要用while。