JavaSe复习笔记

一、java中为什么byte范围是在-128~127?


(1)从表面上看,是0占了一个位置
(2)从补码角度看。因为java用补码表示二进制。补码的最高位是符号位,最高位为“0”表示正数,最高位为“1”表示负数。正数补码为其本身;负数补码为其绝对值各位取反加1;
         1、byte为一字节8位,最高位是符号位,即最大值是01111111,因正数的补码是其本身,即此正数为01111111
十进制表示形式为127
         2、最大正数是01111111,那么最小负是10000000(最大的负数是11111111,即-1)
         3、10000000是最小负数的补码表示形式,我们把补码计算步骤倒过来就即可。10000000减1得01111111然后取反10000000
因为负数的补码是其绝对值取反,即10000000为最小负数的绝对值,而10000000的十进制表示是128,所以最小负数是-128
         4、由此可以得出byte的取值范围是-128到+127

二、==和equals区别?


equals比较两个对象的内容是否相同

== 比较两个对象是否是同一对象。


三、自动装箱和自动拆箱理解

new Integer(2) == 2  true  解释:jvm很聪明,他把已经装好箱子里的2取出来,然后判断是否和右边的2相等。
new Integer(2) == new Integer(2) false 解释;等号两边各创建一个箱子,然后==是判断是否为同一个箱子,但不是判断箱子里面的值是否相等。
Integer.valueOf(2); == Integer.valueOf(2) true 解释:jvm对-128~127直接直接分配箱子,超过的就new一个箱子,然后可能相等,也可能不相等,由系统决定。


Integer.valueOf(2).intvalue() == 2 true 解释:intvlaue是拆箱把里面的值拿出来和2做比较,肯定是相等的

new Integer(2).equals(new Integer(2))  true 解释:equal是判断盒子里面的值是否相等,不是判断盒子是否一个盒子。equals方法先判断是否属于Integer类型,然后再把0bj拆箱作比较的,也就是比较里面的内容。



四、static误区

static只被加载一次。而static方法,不能使用this关键字。
普通函数可以引用静态变量和函数。
语法规定:static是不允许用来修饰局部变量
方便在没有创建对象的情况下来进行调用(方法/变量)。


五、重载和重写的区别

重写方法的规则:

1、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。

2、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。

3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)

4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:

父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。

 

而重载的规则:

1、必须具有不同的参数列表;

2、可以有不责骂的返回类型,只要参数列表不同就可以了;

3、可以有不同的访问修饰符;

4、可以抛出不同的异常;


六、抽象与接口的区别

参数 抽象类 接口
默认的方法实现 它可以有默认的方法实现 接口完全是抽象的。它根本不存在方法的实现
实现 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
构造器 抽象类可以有构造器 接口不能有构造器
与正常Java类的区别 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 接口是完全不同的类型
访问修饰符 抽象方法可以有publicprotecteddefault这些修饰符 接口方法默认修饰符是public。你不可以使用其它修饰符。
main方法 抽象方法可以有main方法并且我们可以运行它 接口没有main方法,因此我们不能运行它。
多继承 抽象方法可以继承一个类和实现多个接口 接口只可以继承一个或多个其它接口
速度 它比接口速度要快 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。

还有一种说法,也就是两者的维度不同。

接口:

(1)从用户角度看问题的

(2)强调合约

(3)强制协作双发无法犯错

(4)接口可以多重实现

抽象类

(1)抽象类可以有成员变量

(2)抽象类可以有部分实现

(3)抽象类不可以多重继承,但是接口可以

七、封装

默认:package private

八、一个有关继承的面试题(2017京东java开发工程师面试题)


解释:new的是谁就调用谁的方法。


九、final关键字作用


(1)修饰类的话,不可以被继承

(2)修饰方法的话,不可以在派生类中重写

(3)修饰变量的话,不可以指向其他的对象。比如final List<String> list;,在方法中就不能对list =new ArrayList<String>;只能在类的初始化时实例化,或者直接在后面实例化。


十、泛型易错点


ArrayList<Integer>是List<Integer>吗?(是的)

List<Integer> 是List<Object>吗?  (不是的)

解释:List<Object> bojList = intlist;

objetList.set(0,"hello");

Integer ele = inilist.get(0);//此时获取的是hello,hello属于String类型。


十一、字节流和字符流的区别

字节流通常处理二进制数组,字符流一般都是处理文本数据。后缀是Stream是字节流,而后缀是Reader,Writer是字符流。


十二、数据库事务的简单理解

1.要么全都做,要么全都不做。比如银行转账,把我的钱扣了,你的钱却没加上这样就是不对的。

2.约束在做之前和做之后都要满足。

3.我做一个事务,你做一个事务,是相互独立的

4.把事务做完后,这个是持久的。



十三、乐观锁(多人抢库存)

在读和写的中间,加入版本控制

select count from product where productId=2;

update product set count =46 where productId=2 and count =47;

当有人在使用此命令时,会显示影响0行,也就是没有修改数据。

乐观锁只能适用于小范围。如果大范围的话,在数据库操作的话就很浪费资源。


十四、浅谈多并发问题

从用户分析:

(1)有可能一个账号通过浏览器一些工具或者一些请求脚本,发出几百次请求。


解决方案:在程序入口处,一个程序只能接受一条请求,其他请求过滤。仅解决了同一个账号,发送N个请求的问题,还保证了后续的逻辑流程的安全。


(2)多个账号发送同一个请求。在早期一些公司,对注册账号没有怎么限制,造成大量的僵尸号

解决方案:a.就是通过设置一些新的验证码,就可以分辨出真实用户。传统的验证码,某些大码平台可以自动打码,因此需要设置新颖的验证码验证机制
b.通过禁用ip。曾经联通有一次举办活动,邀请好友可以获取流量。然后网上就出现了利用接吗平台,注册账号,然后无限刷邀请。过了半个小时后,联通就采用ip时间段限制,每个ip半个小时后才能重新注册。这种做法会误伤,比如有些真实用户的网络场景恰好是同一出口IP的。但是这种做法是最有效的。

(3)多个账号,不同ip发送不同请求。

有些人会重启路由器,或者重新关闭打开网络,系统会重写分配一个ip。账号可以通过注册机瞬间注册好几百个。
解决方法:这种行为基本和真实用户行为差不多,如果在用上面那样做,容易误伤真实用户。可以通过设置业务门槛来解决。比如活跃度不够高的,注册时间比较短的,同一个ip注册上百个账号的。可以过虑一些账号。

从系统分析:

这里只想到用乐观锁。后续再补充吧,毕竟我还是个渣渣


十五、浅谈如何排序10G数据(想法)

通过并行计算可以排序。

(1)将数据拆分到每个节点上:把10g数据分成10个节点,每个节点里面有1g的数据。也就是10路归并。使用二叉树进行排序。


(2)每个节点并行的计算出结果:

在归并节点的时候,如果最小的数丢失,其他得数还得从外部或者磁盘上重新下载分析,这样会使得效率很低。因此可以把一部分数据放到缓存里。
(3)将结果汇总


十六、线程池

线程池:预先建立好线程,等待任务派发。
参数:
corePoolSize:线程池中初始线程数量,可能出于等待状态
maxmumPoolSize:线程池中最大允许线程属性
keepAliveTime:超出corePoolSize部分线程如果等待这些时间将被回收。


十七、java资源管理问题

一、Java垃圾回收。
(1)不被引用的对象会被回收。
(2)垃圾回收包括Minor GC和Full GC
(3)垃圾回收时所有运行暂停


java虚拟机如果发现越来越多的垃圾对象,gc会处理,会占用很大空间,容易造成内存泄漏。
如果创建对象过快过多也会触发gc

二、Java资源管理:

(1)内存会被回收,资源不会被释放。
(2)databaseConnection需要databaseConnection.close()
用try catch来关闭


十八、自写ArrayList

(1)白话文解释思路。。。。

首先定义一个数组
在定义一个size


在初始化中给出数组的大小。


add方法 需要考虑到数组不够用怎么办
1. 赋值
2.如果数组不够用,直接生成个新的数组,把原来的就数组给到新的数组上


凡是方法中用到size的  必须对size检查是否size<0或者size大于数组.length-1

数组拷贝的过程中用到System.arrayCopy();

(2)代码实现

package top.javazhangwei.studyhard;

public class MyArrayList {

	private Object[] value ;
	private int size;

	public MyArrayList() {
		value = new Object[2];
	}
	public int size(){
		return size;
	}

	public void add(Object obj) {
		
			value[size] = obj;
			size++;
			if(size>=value.length-1) {
				int bigsize = size*10;
				Object[] newvalue = new Object[bigsize];
				for(int i=0;i<value.length;i++) {
					newvalue[i] = value[i];
				}
			
				value = newvalue;
			}
	}
	public Object get(int size) {
	if(size<0||size>value.length-1) {
		try {
			throw new Exception();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
		return value[size];
	}
	public void remove(int index) {
		if(size<0||size>value.length-1) {
			try {
				throw new Exception();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		int numMove = size - index ;
		if(numMove>0) {
			System.arraycopy(value, index+1, value, index, numMove-1);
		}
		size--;
	}
}

十九、自写LinkedList

(1)白话文解释思路。。。。

先定义一个node节点。node previost,node next,Object obj.

add方法:就是先判断first==null,如果是空,next和previous都是空。last和first都是这个节点。
如果不为空,直接在last后加。。  怎么能连接起来呢?就是设置last的next是现在这个节点。而现在这个节点也是最后一个。(附上两张图,才发现有时候根据图写代码。容易理解)

get方法:定义一个临时node然后 判断如果first不为空,临时node =first,然后通过for循环便遍历。node = node.getobj(): 还有对index进行范围判断  size<0||index>=size


remove:通过循环遍历找到删除的节点(暂时定义为temp),然后获取temp的上一个节点,和temp的下一个节点。


add(int index,Object obj):获取当前index的节点temp。然后获取temp的上个节点,打断原有节点,然后新的节点和temp的上一个节点,并且和temp相连接。

(2)代码实现。。。。

自己定义一个Node类,这个都会。。。

package MyLinkedList;

public class MyLinkedList {
	private Node first;
	private Node last;
	
	private int size;
	public void add(Object obj) {
		if(first==null) {
			Node node = new Node();
			node.setPrevious(null);
			node.setObj(obj);
			node.setNext(null);
			first = node;
			last = node;
		}else {
			//直接个last加节点
			Node node = new Node();
			node.setPrevious(last);
			node.setObj(obj);
			node.setNext(null);
			
			last.setNext(node);
			last = node;
		}
		size++;
	}
	public int size() {
		return size;
	}
	public Object get(int index) {
		if(size<0||index>=size) {
			try {
				System.out.println("test exception");
				throw new Exception();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		Node temp = null;
		if(first!=null) {
			temp = first;
			for(int i=0;i<index;i++) {
				temp = temp.getNext();
			}
		}
		return temp.getObj();
	}
	public void remove(int index) {

		Node temp = null;
		if(first!=null) {
			temp = first;
			for(int i=0;i<index;i++) {
				temp = temp.getNext();
			}
		}
		if(temp!=null) {
			Node preNode= temp.getPrevious();
			Node nextNode = temp.getNext();
			preNode.setNext(nextNode);
			nextNode.setPrevious(preNode);
		}
		
	}
	public void add(int index,Object obj) {//在index新增一个位置
		Node temp = node(index);
		if(temp!=null) {
			Node n = new Node();
			Node tempPre = temp.getPrevious();
			n.setObj(obj);
			n.setNext(temp);
			temp.setPrevious(n);
			
			tempPre.setNext(n);
			n.setPrevious(tempPre);
			
		}
	}
	public Node node(int index) {

		Node temp = null;
		if(first!=null) {
			temp = first;
			for(int i=0;i<index;i++) {
				temp = temp.getNext();
			}
		}
		return temp;
	}
}

二十、string,StringBuffer,StringBuilder区别


(1)StringBuffer,StringBulider对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。


(2)StringBuilder:线程非安全的;StringBuffer:线程安全的

(3)当字符串缓冲区被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。

当然在大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。

(4)

  a.如果要操作少量的数据用 = String
  b.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

  c.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

猜你喜欢

转载自blog.csdn.net/jav_zhangwei/article/details/78165999