在IP以太网中,当一个上层协议要发包时,有了该节点的IP地址,ARP就能提供该节点的MAC地址。
http VS https
定义:防止了服务器端的一直等待而浪费资源
停止等待、后退N、选择重传
慢启动、拥塞避免、加速递减、快重传快恢复
IPC通信方式:Binder、Content Provider、Socket
Handler、Content Provider、SharePreferences、共享文件、网络
SharePreferences、Content Provider、SQLite数据库、文件(XML、JSON或其他文件形式)、网络存储
操作系统中调度的最小单位元是线程,也叫轻量级进程,在一个进程里可以创建多个进程,这些线程都拥有各自的计数器,堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。因此我们可以这样理解:
要使用UDP来构建可靠的面向连接的数据传输,就要实现类似于TCP协议的超时重传,有序接收,应答确认,滑动窗口、流量控制等机制。实际上就是在传输层的上一层(应用层)实现TCP协议的可靠数据传输机制。
比如使用UDP数据包+序列号,UDP数据报+时间戳等方法,在服务器端进行应答确认机制,这样就会保证不可靠的UDP协议进行可靠的数据传输
基于UDP的可靠传输协议:RUDP、RTP、UDT
连接结束
类加载的过程有三步,装载、连接、初始化。
类从被加载到虚拟机内存开始,到被卸载出内存为止,它的生命周期包括:加载(Loading)、验证(Vertification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading) 7个阶段。其中验证、准备、解析3个部分统称为连接(Linking)
加载时机:创建实例、访问静态变量或方法、反射、加载子类之前
自旋锁:可以使线程在没有取得锁的时候,不会被挂起,而转去执行一个while/空循环
阻塞锁:没得到锁的线程等待或者挂起,sync、Lock
CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术,Doug lea大神在java同步器中大量使用了CAS技术,鬼斧神工的实现了多线程执行的安全性。
CAS的思想很简单:三个参数,一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。
存在的缺点:CAS存在一个很明显的问题,即ABA问题。
同时被static修饰的成员变量和成员方法是独立于该类的,它不依赖于某个特定的实例变量,也就是说它被该类的所有实例共享。所有实例的引用都指向同一个地方,任何一个实例对其的修改都会导致其他实例的变化。
static修饰的变量我们称之为静态变量,没有用static修饰的变量称之为实例变量,它们两者的区别是:
静态变量是随着类加载时完成初始化工作的,它在内存中仅有一个,且JVM只会为它分配一次内存,同时所有的类实例都共享同一个静态变量,可以通过所在的类名来访问它。
实例变量则不同,它是伴随着实例的,每创建一个实例就会产生一个实例变量,它与该实例同生共死。
static修饰的方法我们称之为静态方法,我们通过类名对其进行直接调用。由于它在类加载的时候就存在了,它不依赖于任何实例,所以static方法必须实现,也就是说它不能是抽象方法(abstract)。
Static方法是类中的一种特殊方法,我们只有在真正需要他们的时候才会将方法声明为static。如Math类的所有方法都是静态static的。
被static修饰的代码块,我们称之为静态代码块,静态代码块会随着类的加载一块执行。和静态变量同时进行初始化,根据书写顺序决定初始化的执行顺序。
Static确实是存在诸多的作用,但是它也存在一些缺陷。
java提高篇(六)—–关键字static
将一个类的定义放在另一个类的内部,这就是内部类。
为什么使用内部类?在《Think in Java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地实现一个接口,所以无论外部类是否已经实现了某个接口,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类(设计多个内部类)的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
在Java中内部类主要分为成员内部类、静态内部类、局部内部类、匿名内部类。
在成员内部类中要注意:
- 成员内部类中不能声明任何static变量和方法
- 成员内部类是依附于外部类的,所以只有先创建了外部类才能创建内部类
- 内部类间可以互相调用
public class Outer{
private int size;
public class Inner {
public void dostuff() {
size++;
}
}
public void testTheInner() {
Inner in = new Inner();
in.dostuff();
}
}
public class Demo{
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
inner.dostuff();
}
}
class Outer{
private static int size;
static class Inner {
public void dostuff() {
size++;
System.out.println("size=" + size);
}
}
}
局部类有几个重要特性:
1. 仅在定义它的代码块中是可见的
2. 可以使用定义它的代码块中的任何局部final变量
3. 局部类不可以是static的,也不能定义static成员
4. 局部类不可以使用public、protected、private修饰,只能使用缺省(default)的
5. 局部类可以使abstract的
public class Parcel5 {
//定义在方法中
public Destionation destionation(String str){
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
}
//定义在作用域中
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel5 parcel5 = new Parcel5();
Destionation d = parcel5.destionation("chenssy");
}
}
注意:匿名类必须继承一个父类或实现一个接口。由于匿名内部类不能是抽象类,所以它必须要实现它的抽象父类或者接口里面所有的抽象方法。
匿名内部类是没有构造方法的。
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args){
// 继承 Person 类
new Person() {
public void eat() {
System.out.println("eat something");
}
}.eat();
}
}
java提高篇(七)—–详解内部类
在内部类中的属性和外部方法的参数(形参)两者看似是同一个参数,但实际上并不是,因为Java中是传值不传对象,在匿名内部类中对变量的改变并不会影响到外部的形参。然而站在程序的角度来看这两个根本就是同一个,所以为了保持参数的一致性,就规定使用final来保证形参不被改变。
另一种说法是,Java编译器支持了闭包,但支持地不完整,编译器编译的时候把外部环境方法的形参,拷贝了一份到匿名内部类里。在内部类中修改形参的值,也只是对拷贝的值进行修改,而不会影响到形参的值。为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制。
最关键的原因就是:Java编译器实现的只是capture-by-value
,并没有实现capture-by-reference
。
java为什么匿名内部类的参数引用时final? - 胖胖的回答 - 知乎
java提高篇(九)—–详解匿名内部类
String s1 = "I" + "Love";
String s2 = "I" + new String("Love");
String s3 = "ILove";
String I = "I";
String s4 = I + "Love";
String s5 = new String("ILove");
String s55 = new String("ILove");
String s6 = new String("I") + "Love";
String Love = "Love";
String s7 = I + Love;
LogUtils.e("s1 == s2" + (s1 == s2));
LogUtils.e("s1 == s4" + (s1 == s4));
LogUtils.e("s1 == s3" + (s1 == s3)); //true
LogUtils.e("s2 == s3" + (s2 == s3));
LogUtils.e("s3 == s4" + (s3 == s4));
LogUtils.e("s3 == s5" + (s3 == s5));
LogUtils.e("s5 == s55" + (s5 == s55));
LogUtils.e("s3 == s6" + (s3 == s6));
LogUtils.e("s5 == s6" + (s5 == s6));
LogUtils.e("s5 == s6" + (s5 == s6));
LogUtils.e("s3 == s7" + (s3 == s7));
LogUtils.e("s4 == s7" + (s4 == s7));
LogUtils.e("str" + 1 + 2); //str12
LogUtils.e("str" + (1 + 2)); //str3
是。
线程分为守护线程和非守护线程(即用户线程)。
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
守护线程最典型的应用就是 GC (垃圾回收器)
存在。
假设 i 为整型int,那么当i为int能表示的最大整数时,i+1就溢出变成负数了,此时不就
第2和3种方法使用了反射,具体实现如下:
Employee emp = (Employee) Class.forName("com.tin.chigua.Employee").newInstance();
//或者
Employee emp2 = Employee.class.newInstance();
Constructor constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();
事实上,使用Class类的newInstance()方法内部调用了Constructor的newInstance()方法,所以后者的效率更高,被更多框架所使用。
为了反序列化一个对象,我们需要让我们的类实现Serializeable接口
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp4 = (Employee) in.readObject();
除了第一个方法,其他四个方法全都转变为invokevirtual(创建对象的直接方法),第一个方法转变为了两个调用,new和invokespecial(构造函数调用)。
Android大厂面试题锦集(BAT TMD JD 小米)
Java三十个面试题总结