概述
细节决定成败(二)
有什么写的不好的一定要指出哦。
怎么在不使用“+”的情况下,对两个数进行相加
public int plus(int a,int b){
//两个临时变量
int aTemp = 0,bTemp = 0;
while(b!=0){
aTemp = a ^ b;
btemp = (a & b) << 1;
a = aTemp;
b = bTemp;
}
return a;
}
那如何在不创建临时变量的情况下进行交换两个数呢?
public void swap(int a,int b){
// a 中存放两数互异的点位
a ^= b;
// 取反b中不同于a的点位,也就是实现了b=a
b ^= a;
// 取反a中不同于b的点位,也就是实现了a=b
a ^= b;
}
如果把A转换成B,需要改变多少位?
两个数做异或的结果就是两个数差异所在,然后只需计算这个结果中有多少个 1 即可。
public int convertA2B(int A,int B){
int n = A ^ B;
int count = 0;
while(n != 0){
//n-1 是将n的最低为置零
n &= n-1;
count++;
}
return count;
}
Thread的sleep()和yield()方法的区别
- 1 、sleep()方法给其他线程机会不会考虑线程的优先级别,而yield()方法只会给相同运行级别或更高运行级别的线程运行(只是概率更高)
- 2 、线程执行sleep()方法就会进入阻塞状态,执行yield()方法就会转入就绪状态
- 3 、sleep()方法声明抛出InterruptException,而yield()没有声明任何异常
- 4 、sleep()方法比yield()方法具有更好的移植性
EJB (Enterprise java Beans)规范中EJB禁止的操作有哪些?
- 1 、不能操作线程和线程API(线程API指非线程对象的方法如notify,wait等);
- 2 、不能操作awt;
- 3 、不能实现服务器功能;
- 4 、不能对静态属性存取;
- 5 、不能使用IO操作直接存取文件系统;
- 6 、不能加载本地库;
- 7 、不能将this作为变量和返回;
- 8 、不能循环调用.
怎样判断mysql字段应该建立索引
- 判断该kfid字段是否应该建立索引 (0,1] 越大越应该建立
select count(distinct(kfid))/count(*) as Selectivity from patient_prescription
对象的深度克隆
- 对象属性一个个克隆,前提是都要实现Cloneable接口
public Object clone(){
CloneClass o = null;
try{
o = (CloneClass)super.clone();
o.test = (Class1)t.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
- 通过序列化与反序列化
a. 使用工具类
this.para = (Map<String, Object>) SerializationUtils.clone((HashMap<String, Object>)po.getPara());
b. 序列化成流,再操作, 必须实现Serializable接口
//深拷贝
public Object clone()
{
try
{
// save the object to a byte array
//将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(this);
out.close();
// read a clone of the object from the byte array
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object ret = in.readObject();
in.close();
return ret;
}
catch (Exception e)
{
return null;
}
}
- 用fastjson从Object转成json,然后转回object,本质上是反射
private Object deepCopyByJson(Object obj) {
String json = JSON.toJSONString(obj);
return JSON.parseObject(json, Object.class);
}
- 工具类BeanUtils和PropertyUtils进行对象复制
Student stu1 = new Student();
stu1.setNumber(1111);
stu1.setName("张三");
Student stu2 = new Student();
BeanUtils.copyProperties(stu2,stu1);
接口的特点
- 接口中的数据成员为final static
- 接口中的数据成员为public abstract
- 实现接口的类不一定必须实现该接口的所有抽象方法(抽象类就是一个)
一级、二级、三级封锁协议
一级封锁协议需要在修改数据时进行加锁,而读数据时不会进行加锁,所以不能保证可重复度和不读脏数据。
二级封锁协议:是在读取数据前进行加锁,读完后解锁,防止了丢失修改可以保证不会脏读但不能保证可重复读。
三级封锁协议:在读数据时进行加锁,直到事务结束才解锁,保证不会脏读和可重复读
单CPU系统中通常采用两级处理器调度
- 作业调度是从慢速存储设备中的后备队列中挑选作业加载到主存中。
- 进程调度是从主存中的就绪队列中挑选进程占用处理器运行。
部分网络协议采用的是TCP还是UDP
- SNMP:简单网络管理协议,使用无连接UDP。
- SSH:安全外壳协议,采用面向连接的TCP协议传输,应用22号端口,安全系数较高。
- DHCP:动态主机配置协议,使用UDP进行工作。
- TELENT:是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。
对含有31个元素的序列采用直接选择排序算法排序,在最坏情况下需要进行多少次移动才能完成排序?
总共需要(n-1)次交换,但是每次交换都需要用到临时变量,temp = a; a = b; b = temp; 这就有三次移动了,所以总共有 3*(n-1)次移动,答案就是 3 * (31 -1) = 90次
进程间通信方式
- 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程间的亲缘关系通常是指父子进程关系。
- 有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。
- 信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 消息队列(message queue):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
- 共享内存(shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其它通信机制,如信号量,配合使用,来实现进程间的同步和通信。
- 套接字(socket):套接字也是一种进程间通信机制,与其它通信机制不同的是,它可用于不同及其间的进程通信。
类加载机制习题
1. 根据类加载器加载类的初始化原理,推断下面代码输出什么?
public class Test {
public static void main(String[] args) throws Exception{
ClassLoader classLoader=ClassLoader.getSystemClassLoader();
Class clazz=classLoader.loadClass("A");
System.out.print("Test");
clazz.forName("A");
}
}
class A{
static {
System.out.print("A");
}
}
答案是:TestA
因为classLoader.loadClass(“A”);只是将A加载进内存,并没有对该类首次主动使用,所以没有初始化,就不会执行clinit();
clazz.forName(“A”);通过反射获取到A的内存中的数据结构对象,对类进行了首次使用,才会触发初始化,执行clinit();
静态块只在第一次初始化的时候才会执行一次
对类的主动使用:
- 创建类的实例
- 访问某个类或者接口的静态变量,或者对该静态变量赋值。
- 调用类的静态方法。
- 反射(Class.forName(“”))
- 初始化类的子类
- java虚拟机启动时被标明为启动类的类
2. 继承是JAVA语言的一个特性,针对类的继承,虚拟机会如何进行父类和子类的初始化加载呢?请阅读代码选择出该段代码的输入结果。
public class Test {
public static void main(String[] args) {
System.out.print(B.c);
}
}
class A {
public static String c = "C";
static {
System.out.print("A");
}
}
class B extends A{
static {
System.out.print("B");
}
}
答案是:“AC”。
通过子类引用父类的静态字段,不会导致子类初始化,只会导致父类初始化。
3. 同上题类似
public class Test {
public static void main(String[] args) {
System.out.print(B.c);
}
}
class A {
static {
System.out.print("A");
}
}
class B extends A{
static {
System.out.print("B");
}
public final static String c = "C";
}
答案是:“C”。常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
会导致类初始化的情况:
- main方法所在的类,总会被首先初始化。
- 首次访问这个类的静态变量或者静态方法时。
- 子类初始化,如果父类还没有初始化,会引发父类初始化。
- 子类访问父类的静态变量,只会触发父类的初始化。
- Class.forName("**"), new 会导致初始化。
不会导致类初始化的情况
- 访问类的static final静态常量(基本类型和字符串)不会触发初始化。
- 类对象.class不会触发初始化。
- 创建该类的数组不会触发初始化。
- classLoader.loadClass(“A”) 加载类到内存中也不会触发初始化。
4.同上继续
public class Test {
public static void main(String[] args) {
System.out.println(Test2.a);
}
}
class Test2{
static {
System.out.print("OK");
}
public static final String a=new String("JD");
}
答案是:“JDOK”
读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)时 才初始化,此时的a是运行时常量.
和上一题的区别在于这里new String(“JD”);首先会在常量池中的一个操作就是创建jd字符串,但是在堆中的操作,却是要等到初始化阶段才行,所以此时的a是一个经过初始化节点的常量,所以static块当然也会被执行。
5.同上继续
public class Test {
public static void main(String[] args) {
System.out.println(Test2.a);
}
}
class Test2{
public static final String a=new String("JD");
static {
System.out.print("OK");
}
}
答案是 “OKJD”
遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则必须先触发其初始化。
最常见的生成这 4 条指令的场景是:
- 使用 new 关键字实例化对象的时候;
- 读取或设置一个类的静态字段(被 final 修饰、已在编译期把结果放入常量池的静态字段除外)的时候;
- 以及调用一个类的静态方法的时候。
6.同上继续
public class Test {
public static void main(String[] args) {
System.out.println(Test2.a);
}
}
class Test2{
public static final String a="JD";
static {
System.out.print("OK");
}
}
答案是 “JD”
"JD"常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
Java值传递
public class Main {
private static int x = 10;
private static Integer y = 10;
public static void updateX(int value) {
value = 3 * value;
}
public static void updateY(Integer value) {
value = 3 * value;
}
public static void main(String[] args) {
updateX(x);
updateY(y);
}
}
执行以上程序后,x和y的值分别是多少?
答案是 10,10
因为Java只有值传递,所以x的值不会变,而Integer传个引用过去,但是Integer和String一样是final的,进行修改后会生成一个新的值放在常量池中,并且会有一个新的引用指向他,所以原本的引用压根就没变。
最后
以上就是魁梧凉面为你收集整理的细节决定成败(二)的全部内容,希望文章能够帮你解决细节决定成败(二)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复