1、线程
线程创建方式继承Thread类和实现Runable接口,重写run方法
使用callable和future创建线程,使用线程池
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVathKHe-1583845715739)(https://media.geeksforgeeks.org/wp-content/uploads/threadLifeCycle.jpg)]
2、线程池
**线程池可重复使用先前创建的线程来执行当前任务,并为线程周期开销和资源颠簸问题提供了解决方案。**由于在请求到达时线程已经存在,因此消除了线程创建带来的延迟,从而使应用程序具有更高的响应速度。
-
Java提供了Executor框架,该框架以Executor接口,其子接口ExecutorService和ThreadPoolExecutor类为中心,后者实现了这两个接口。通过使用执行程序,仅需实现Runnable对象并将其发送给执行程序即可执行。
-
它们使您可以利用线程的优势,而专注于希望线程执行的任务,而不是线程机制。
-
要使用线程池,我们首先创建一个ExecutorService对象,并将一组任务传递给它。ThreadPoolExecutor类允许设置核心和最大池大小。由特定线程运行的可运行对象按顺序执行。
-
使用线程池的风险
-
-
- **死锁:**尽管死锁可以在任何多线程程序中发生,但是线程池会引入另一种死锁情况,在这种情况下,由于线程无法执行,所有正在执行的线程都在等待队列中被阻塞线程的结果。
- **线程泄漏:**如果从线程池中删除线程以执行任务,但任务完成后没有返回线程,则会发生线程泄漏。例如,如果线程引发异常,并且池类没有捕获此异常,则线程将直接退出,从而将线程池的大小减小一个。如果重复多次,则该池最终将变为空,并且没有线程可用于执行其他请求。
- **资源释放:**如果线程池很大,那么浪费时间在线程之间进行上下文切换。如所解释的,具有比最佳数量更多的线程可能会导致饥饿问题,从而导致资源崩溃。
-
-
重要事项
-
-
- 不要将同时等待其他任务结果的任务排队。如上所述,这可能导致死锁的情况。
- 使用线程进行长寿命操作时要小心。它可能导致线程永远等待,并最终导致资源泄漏。
- 线程池必须在末尾显式结束。如果未完成,则程序将继续执行,并且永远不会结束。在池上调用shutdown()以结束执行程序。如果您尝试在关闭后将另一个任务发送给执行器,它将抛出RejectedExecutionException。
- 需要了解任务以有效地调整线程池。如果任务之间有很大差异,则有必要对不同类型的任务使用不同的线程池,以便对其进行适当的调整。
-
-
调优线程池
-
- 线程池的最佳大小取决于可用处理器的数量和任务的性质。在仅处理计算类型的队列的N处理器系统上,最大线程池大小为N或N + 1将实现最大效率,但是任务可能会等待I / O,因此在这种情况下,我们要考虑比率请求的等待时间(W)和服务时间(S);导致最大池大小为N *(1+ W / S),以实现最大效率。
-
线程池是用于组织服务器应用程序的有用工具。它在概念上非常简单明了,但是在实现和使用它时要注意几个问题,例如死锁,资源崩溃。使用执行程序服务使其更易于实现。
-
3、反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
与Java反射相关的类如下:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
Class类
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。
- 获得类相关的方法
方法 | 用途 |
---|---|
asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 |
Cast | 把对象转换成代表类或是接口的对象 |
getClassLoader() | 获得类的加载器 |
getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 |
forName(String className) | 根据类名返回类的对象 |
getName() | 获得类的完整路径名字 |
newInstance() | 创建类的实例 |
getPackage() | 获得类的包 |
getSimpleName() | 获得类的名字 |
getSuperclass() | 获得当前类继承的父类的名字 |
getInterfaces() | 获得当前类实现的类或是接口 |
- 获得类中属性相关的方法
方法 | 用途 |
---|---|
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
- 获得类中注解相关的方法
方法 | 用途 |
---|---|
getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() | 返回该类所有的公有注解对象 |
getDeclaredAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() | 返回该类所有的注解对象 |
- 获得类中构造器相关的方法
方法 | 用途 |
---|---|
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
- 获得类中方法相关的方法获取私有方法添加setAccessible(true);
方法 | 用途 |
---|---|
getMethod(String name, Class…<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
- 类中其他重要的方法
方法 | 用途 |
---|---|
isAnnotation() | 如果是注解类型则返回true |
isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定类型注解类型则返回true |
isAnonymousClass() | 如果是匿名类则返回true |
isArray() | 如果是一个数组类则返回true |
isEnum() | 如果是枚举类则返回true |
isInstance(Object obj) | 如果obj是该类的实例则返回true |
isInterface() | 如果是接口类则返回true |
isLocalClass() | 如果是局部类则返回true |
isMemberClass() | 如果是内部类则返回true |
Field类
Field代表类的成员变量(成员变量也称为类的属性)。
方法 | 用途 |
---|---|
equals(Object obj) | 属性与obj相等则返回true |
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj, Object value) | 设置obj中对应属性值 |
Method类
Method代表类的方法。
方法 | 用途 |
---|---|
invoke(Object obj, Object… args) | 传递object对象及参数调用该对象对应的方法 |
Constructor类
Constructor代表类的构造方法。
方法 | 用途 |
---|---|
new Instance(Object… initargs) | 根据传递的参数创建类的对象实例 |
4、反射创建对象的方式
//1.1.对象.getClass();获取对象
//1.2.类.class
//1.3.Class.forName(“包名.类名”);
//1.源头:获取Class对象,用三种方式
phone iPhone=new phone();
//1.1.对象.getClass();获取对象
Class<?> clazz1 = iPhone.getClass();
//1.2.类.class
clazz1=phone.class;
//1.3.Class.forName("包名.类名");
clazz1 = Class.forName("test.phone");
//2.创建对象
//2.1通过newInstence()
phone instance1 = (phone) clazz1.newInstance();
//2.2先调用构造器,再通过newInstence()创建
Object instance2 = clazz1.getConstructor().newInstance();
5、反射怎么调用方法对象?
obj.getClass().getMethod(“方法名!!!”)
6、设计模式用到哪些?单例模式是怎么实现的?
-
/** * 饿汉-单例模式 */ public class Singleton1 { //1.定义私有静态变量,类型为类类型 //直接创建好对象,不论到底会用到用不到,故称为饿汉式 private static Singleton1 instance = new Singleton1(); //2.定义私有构造函数 private Singleton1(){ } //3.定义公共静态方法,返回私有静态变量 public static Singleton1 getInstance(){ return instance; } } /** * 懒汉-单例模式 */ public class Singleton2 { //1.定义私有静态变量,类型为类类型, // 先不创建,等用到时再创建(正是由于等用到时才创建,故而才称为懒汉式) private static Singleton2 instance = null; //2.定义私有构造函数 private Singleton2(){ } //3.定义公共静态方法,返回私有静态变量 // public static Singleton2 getInstance(){//线程不安全的 public static synchronized Singleton2 getInstance(){// 线程安全,通过synchronize保证线程安全 if(instance == null){ instance = new Singleton2(); } return instance; } } /** * 内部类创建方式-单例模式 * 这种方式是线程安全的 */ public class Singleton3 { //1.定义静态内部类,类里面有静态内部属性,为类类型 private static class SingletonInnerClass{ private static final Singleton3 instance = new Singleton3(); } //2.定义私有构造函数 private Singleton3(){ } //3.定义公共静态方法,返回内部类的静态常量 public static Singleton3 getInstance(){ return SingletonInnerClass.instance; } }
spring中常用的设计模式达到九种,我们举例说明:
第一种:简单工厂
又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。如下配置,就是在 HelloItxxz 类中创建一个 itxxzBean。
<beans> <bean id="singletonBean" class="com.itxxz.HelloItxxz"> <constructor-arg> <value>Hello! 这是singletonBean!value> </constructor-arg> </ bean> <bean id="itxxzBean" class="com.itxxz.HelloItxxz" singleton="false"> <constructor-arg> <value>Hello! 这是itxxzBean! value> </constructor-arg> </bean> </beans>
第二种:工厂方法(Factory Method)
通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。
螃蟹就以工厂方法中的静态方法为例讲解一下:
import java.util.Random; public class StaticFactoryBean { public static Integer createRandom() { return new Integer(new Random().nextInt()); } }
建一个config.xm配置文件,将其纳入Spring容器来管理,需要通过factory-method指定静态方法名称
<bean id=“random”
class=“example.chapter3.StaticFactoryBean” factory-method=“createRandom” //createRandom方法必须是static的,才能找到 scope=“prototype”
/>
测试:
public static void main(String[] args) {
//调用getBean()时,返回随机数.如果没有指定factory-method,会返回StaticFactoryBean的实例,即返回工厂Bean的实例 XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(“config.xml”)); System.out.println(“我是IT学习者创建的实例:”+factory.getBean(“random”).toString());
}
第三种:单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
核心提示点:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定
第四种:适配器(Adapter)
在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。
Adapter类接口:Target
public interface AdvisorAdapter { boolean supportsAdvice(Advice advice); MethodInterceptor getInterceptor(Advisor advisor); } MethodBeforeAdviceAdapter类,Adapter class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); } }
第五种:包装器(Decorator)
在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在spring和hibernate框架中总是配置一个数据源,因而sessionFactory的dataSource属性总是指向这个数据源并且恒定不变,所有DAO在使用sessionFactory的时候都是通过这个数据源访问数据库。但是现在,由于项目的需要,我们的DAO在访问sessionFactory的时候都不得不在多个数据源中不断切换,问题就出现了:如何让sessionFactory在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能不能在spring的框架下通过少量修改得到解决?是否有什么设计模式可以利用呢?
首先想到在spring的applicationContext中配置所有的dataSource。这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL等,也可能是不同的数据源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。然后sessionFactory根据客户的每次请求,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
第六种:代理(Proxy)
为其他对象提供一种代理以控制对这个对象的访问。 从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。
spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。
第七种:观察者(Observer)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
第八种:策略(Strategy)
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
spring中在实例化对象的时候用到Strategy模式
在SimpleInstantiationStrategy中有如下代码说明了策略模式的使用情况:
第九种:模板方法(Template Method)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
Template Method模式一般是需要继承的。这里想要探讨另一种对Template Method的理解。spring中的JdbcTemplate,在用这个类时并不想去继承这个类,因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。这可能是Template Method不需要继承的另一种实现方式吧。
7、工厂模式有哪些?
简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。
工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。
8、常用的设计模式
单例模式
代理模式:动态代理和静态代理
观察者模式
装饰模式
简单工厂模式
9、面向对象的四大特征
抽象
定义:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面,抽象只关注对象的哪些属性和行为,并不关注这此行为的细节是什么
封装
定义:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口.面向对象的本质就是将现实世界描绘成一系列完全自治,封闭的对象,可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。封装给对象提供了隐藏内部特性和行为的能力,对象提供一些能这被其它对象访问的方法来改变它内部的数据。
2.1.提供构造方法(有了构造方法才能通过new去构建一个对象 1.构造方法必须和类名称一样2.构造方法不能有返回值)
继承(关键字:extends)
目的:对父类和方法的复用
继承是从已有类得到继承信息创建新类的过程,继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段.子类继承父类属性(静态特征)和方法(动态特征),继承必须遵循封装当中的控制访问
多态
多态性是指允许相同或不同子类型的对象对同一消息作出不同响应
重载:同一个动作作用在同一个对象上拥有不同的解释 overload
重载又称静态多态,编译时多态
重写:同一个动作作用在不同的对象上拥有不同的解释 override
重写又称动态多态,运行时多态
狭义的多态指重写
五大设计原则
单一职责原则
里氏替换原则
依赖原则
接口分离原则
开放封闭原则
10、重写与重载的区别
重写必须存在于字符类继承关系的类中,子类重写父类方法,方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private) 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
重载存在于类中,区别于同样的方法名,不同的参数类型和参数返回值同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
一. Java基础部分
1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?
可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。
一个文件中可以只有非public类,如果只有一个非public类,此类可以跟文件名不同
2、说说&和&&的区别。
&和&&都可以用作逻辑与的运算符,&&为短路与,&不是短路与。
另外&可以做为整数的位运算符
例1:对于if(str != null&& !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。
例2:If(x33 &++y>0) y会增长,If(x33 && ++y>0)不会增长
3、在JAVA中如何跳出当前的多重嵌套循环?
\1. Break + 标签
\2. 使用多个条件判断
\3. 使用方法的return
在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break语句,即可跳出外层循环。例如,
ok: for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println(“i=” + i + “,j=” + j);
if (j == 5)
break ok;
}
}
另外,我个人通常并不使用标号这种方式,而是让外层的循环条件表达式的结果可以受到里层循环体代码的控制,例如,要在二维数组中查找到某个数字。
int arr[][] ={ {1,2,3},{4,5,6,7},{9}};
boolean found = false;
for(int i=0;i<arr.length&& !found;i++) {
for(int j=0;j<arr[i].length;j++){
System.out.println(“i=” + i + “,j=” + j);
if(arr[i][j] ==5) {
found = true;
break;
}
}
}
第三种,使用方法的return
private static int test() {
int count = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
count++;
System.out.println(“i=” + i + “,j=” + j);
if (j == 5) {
return count;
}
}
}
return 0;
}
4、switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
作用在byte, short, char, int, enum
封装类对象,其它基本数据类型及引用数据类型都不能做为case的条件
6、用最有效率的方法算出2乘以8等於几?
2 << 3
因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2 << 3。
7、请设计一个一百亿的计算器
如果只是大整数运算,使用BigInteger就可以
如果有浮点数据参与去处,需要使用BigDecimal进行运算
Java中基本类型的浮点数运算是不精确的,需要使用BigDecimal运算,尤其是金融、会计方向的软件
8、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
引用变量不能重新赋值,但是引用指向的对象的内容可以变化
例1:final StringBuffer a=new StringBuffer(“immutable”);
a=new StringBuffer("");
有编译错
例2:
final StringBuffer a=new StringBuffer(“immutable”);
a.append(“123”);
正确
9、"=="和equals方法究竟有什么区别?
他们的区别主要存在在引用数据类型上
==为比较两侧的对象是否同一对象,是用内存地址来比较的
equals是方法,默认是用内存地址比较,重写后,主要是用来比较两侧的对象的值是否相同,和equals方法中的实现有关
==可以两侧都为null,但equals左侧的引用指向的对象不能空,不然有NullPointerException
除非需要比较两个引用指向的对象是同一对象,一般都使用equals方法进行比较。尤其是String之类的值对象,另外,常量尽量放在比较的左侧
10、静态变量和实例变量的区别?
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。
总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
11、是否可以从一个static方法内部发出对非static方法的调用?
不可以。因为非static方法(实例方法)是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个static方法内部发出对非static方法的调用。
12、Integer与int的区别
int是java提供的8种原始数据类型之一,意思整型,占用4字节。
Integer是java为int提供的封装类,是引用数据类型。
int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况。
例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer
在JSP开发中,Integer的默认为null,所以用el表达式在文本框中显示时,值为空白字符串,而int默认的默认值为0,所以用el表达式在文本框中显示时,结果为0,所以,int不适合作为web层的表单数据的类型。
在Hibernate中,如果将OID定义为Integer类型,那么Hibernate就可以根据其值是否为null而判断一个对象是否是临时的,如果将OID定义为了int类型,还需要在hbm映射文件中设置其unsaved-value属性为0。
另外,Integer提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量。
13、Math.round(11.5)等于多少? Math.round(-11.5)等于多少?
Math类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应,例如,ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor的英文意义是地板,该方法就表示向下取整,Math.ceil(11.6)的结果为11,Math.ceil(-11.6)的结果是-12;最难掌握的是round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
14、请说出作用域public,private,protected,以及不写时的区别
这四个作用域的可见范围如下表所示。
说明:如果在修饰的元素上面没有写任何访问修饰符,则表示friendly/default。
作用域 | 当前类 | 同package | 子孙类 | 其他package |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
friendly | √ | √ | × | × |
private | √ | × | × | × |
备注:只要记住了有4种访问权限,4个访问范围,然后将全选和范围在水平和垂直方向上分别按排从小到大或从大到小的顺序排列,就很容易画出上面的图了。
15、Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
Overload是重载的意思,Override是覆盖的意思,也就是重写。
Overload和Override有共同之处,两个方法的方法名都必须相同,如果不同,既不构成Overload,也不构成Override。
- Override必须发生在父子类之间,Overload可以不在父子类之间
- Override的特点:
a) 参数列表完全相同:个数相同、类型相同、顺序相同
b) 子类的返回值不能比父类的返回值范围大
c) 子类方法抛出的异常不能比父类方法抛出的异常范围大
d) 修饰符只能为public、protected、friendly,不能为private
e) 父子类方法不能使用static修饰
- 重载发生在同一个类或父子类之间,重写中参数列表至少满足个数不同、类型不同、顺序不同中的一个条件,不包含父子类之间的static方法
17、写clone()方法时,通常都有一行代码(不是必须有),是什么?
clone 有缺省行为,**super.clone();**因为首先要把父类中的成员复制到位,然后才是复制自己的成员。
18、面向对象的特征有哪些方面
\1. 封装,隐藏内部实现,只暴露公共行为
\2. 继承,提高代码的重用性
\3. 多态,体现现实生活中相似对象的差异性
\4. 抽象,抽取现实世界中相似对象的共同点
19、java中实现多态的机制是什么?
通过继承父类或实现接口。不同子类或实现类对同一父类方法有不同的实现。根据对象调用相应的实现方法。另外对于相似的方法,可以使用重载。
20、abstract class和interface有什么区别?
含有abstract修饰符的class即为抽象类,abstract类不能创建的实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
下面比较一下两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
\4. 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
\5. 抽象类中可以包含静态方法,接口中不能包含静态方法
\6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
\7. 一个类可以实现多个接口,但只能继承一个抽象类。
下面接着再说说两者在应用上的区别:
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约;
而抽象类在代码实现方面发挥作用,可以实现代码的重用。
21、abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
abstract的method不可以是static的,因为抽象的方法是要被子类实现的,而static与子类扯不上关系!
native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与abstract混用。
synchronized和abstract合用的问题不能共用,abstract方法只能存在于抽象类或接口中,它不能直接产生对象,而默认synchronized方法对当前对象加锁,没有对象是不能加锁。
另外synchronized不能被继承,子类继承时,需要另加修改符。
22、什么是内部类?Static Nested Class和Inner Class的不同。
内部类就是在一个类的内部定义的类。内部可以定义在除参数位置上的任意位置。印象中有四种方式。
\1. 静态内部类需要使用static修饰,而普通内部类不能使用static修饰
\2. 静态内部类只能定义在和属性同级,普通内部类可以定义在除参数位置以外的任意位置
\3. 静态内部类必需有名称,而普通内部类可以是匿名的
\4. 静态内部类没有this引用,只此只能访问外部类的静态成员,而普通内部类可以访问外部类的全部成员
\5. 静态内部类访问外部类的同名函数时,使用“外部类名.方法名”即可,而普通内部类需要使用“外部类名.this.外部方法”
\6. 静态内部类可以定义静态方法,而普通内部类不能定义静态方法
23、内部类可以引用它的包含类的成员吗?有没有什么限制?
\1. 如果内部类为静态内部类,只能调用外部类的静态成员;如果有重名成员,需要用“外部类名.成员名”访问;不能调用外部类的对象成员。
\2. 如果内部类为非静态内部类,则可以调用外部类的所有成员;如果有重名成员,需要使用“外部类名.this.外部方法”
24、String是最基本的数据类型吗?
基本数据类型包括byte、int、char、long、float、double、boolean和short。
String是引用数据类型。
java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer/StringBuilder类
27、String和StringBuffer的区别
这两个类都实现了CharSequence接口。
\1. 类型不同,因为不是一个类,也没有继承关系,做参数时不能共用
\2. String对象是不可变对象,不能修改值。而StringBuffer是可变对象,能修改值。
\3. 拼接字符串时,String会产生新对象,而StringBuffer只是增加新字符,不产生新对象,因此效率高。
\4. String覆盖了equals方法和hashCode方法,而StringBuffer没有覆盖equals方法和hashCode方法,所以,将StringBuffer对象存储进Java集合类中时会出现问题。
28、如何把一段逗号分割的字符串转换成一个数组?
如果不查jdk api,我很难写出来!我可以说说我的思路:
- 用正则表达式,代码大概为:String [] result = orgStr.split(“,”, -1);
- 用 StingTokenizer ,代码为:
StringTokenizer tokener = new StringTokenizer(s, “,”);
String[] result = new String[tokener.countTokens()];
Integer i = 0;
while (tokener.hasMoreTokens()) {
result[i++] = tokener.nextToken();
}
- 最笨的办法,用String.indexOf()
int index = -1;
int oldIndex = 0;
List ss = new ArrayList();
while ((index = s.indexOf(’,’, index + 1)) != -1) {
ss.add(s.substring(oldIndex, index));
oldIndex = index + 1;
}
if (s.charAt(s.length() - 1) == ‘,’) {
ss.add("");
}
String[] array = ss.toArray(new String[ss.size()]);
System.out.println(Arrays.toString(array));
30、final, finally, finalize的区别。
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成final类型
final int[] number = { 20 };
new Thread() {
@Override
public void run() {
for (int k = 0; k < 20; k++) {
number[0]++;
}
}
}.start();
Thread.sleep(10);
System.out.println(number[0]);
finally是异常处理语句结构的一部分,表示总是执行,用来释放资源。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用
31、运行时异常(Runtime)与检查异常(Checked)有何异同?
异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。
32、error和exception有什么区别?
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出,不可能指望程序能处理这样的情况。exception表示一种设计或实现问题,也就是说,它表示如果程序运行正常,从不会发生的情况。
33、Java中的异常处理机制的简单原理和应用。
异常是指java程序运行时(非编译)所发生的非正常情况或错误。
Java使用面向对象的方式来处理异常,它把程序中发生的每个异常也都分别封装到一个对象中,该对象中包含有异常的信息。
Java可以自定义异常类,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。
- Error表示应用程序本身无法克服和恢复的一种严重问题,程序只有退的份了,例如说内存溢出和线程死锁等系统问题。
- Exception表示程序还能够克服和恢复的问题,其中又分为运行时异常和检查异常,运行时异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉。例如,数组越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException);检查异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。
Java为运行时异常和检查异常提供了不同的解决方案,编译器强制检查异常必须try…catch处理或用throws声明继续抛给上层调用方法处理,所以检查异常也称为checked异常,而运行异常可以处理也可以不处理,所以编译器不强制用try…catch处理或用throws