- int 4字节, short 2字节, long8字节, byte 1字节, float 4字节 (F),double 8字节 (D) char 2字节
- 十六进制 前边加 ox, 八进制 前边加 o
- & 与 相同为真. | 或 . ^异或 相异为真,相同为假. ~ 非
- << 左移变大. 右移变小.
- StringBuilder 单线程使用, StringBuffer 多线程使用
- BigInteger 任意长度整数. BigDecimal 任意长度浮点数
- 数组的长度是固定不可变的.
- final修饰的成员,在构造函数后不可更改,修饰的类不可被继承,final方法不可被重写
- static 修饰的成员被类共享.
- 静态方法不能访问本类的实例对象.
- 方法的形参是无法修改传入的基本数据类型的值的,如下
int a =6;
public static void add(int x){//此时形参只是得到了a的一份拷贝.
x=10;
}
add(a);// 没用的 a的值不会变.
- 方法的形参可以改变对象的值,因为形参和实际传入的实参会指向同一个对象
Ad s=new Ad();
public static void add(Ad a){ //a也是拿到s的一份拷贝,共同指向同一个对象
a.ee=10;
}
add(s);// s的ee会变为10;
- Java 总是采用值调用,方法得到的是所有参数值的一个拷贝.所以,方法不能修改基本数据类型的参数,方法可以改变一个形参的状态,方法不能实现让形参指向新的对象.
- 有代码块时, 先执行代码块在执行构造方法.类加载时,就执行静态块,静态成员的方法.按照类定义顺序执行.
- java 不对局部变量初始化,会对类的成员变量初始化.
- 用final,static,private修饰的方法,编译器可以准确的找到,称为静态绑定,而通过参数列表和方法名字在运行时被编译器查找,称为动态绑定.
- 动态绑定过程
假如 C类的对象 x调用 f(param) 方法.
1.编译器查看对象的声明类和方法名,可能f方法存在多个重载或重写的方法,编译器会得到所有的f方法.
2.编译器产看调用方法的形参类型和数量,如果上边的所有方法存在形参类型和数量完全匹配的方法f(param),就选择这个方法.这个过程称为 重载解析.此时编译器得到了方法的名字和参数类型及数量.
3.编译器生成一条调用 f(param)方法的指令.供虚拟机调用.
4.虚拟机调用于x类型最接近的类的方法.如果C有f(param)就调用C的方法,或者调用C的父类的f(param)方法.
5.实际上,虚拟机预先为每个类创建一个方法表, - 抽象方法必须在抽象类中,抽象类不能实例话,抽象类可以有非抽象方法.
- 访问修饰符 private -本类可见 public -所有类可见 protected-本包及子类可见 默认 -本包可见
- 反射. Class类,在运形时保存每个对象的类的属性.Class对象表示特定类的属性.
Field,描述类的成员. getType 返回成员的所属类型的Class对象
Method,秒数类的方法, 有得到参数类型的方法和得到返回类型的方法
Consxtructor 描述类的构造函数. 有得到参数类型的方法
方法简介
Class
Field[] getFields() //得到该类及父类的public 成员
Field[] getDeclaredFields() //得到该类所有成员,不包含父类,包含private
Method[] getMethod()//得到该类及父类public所有方法
Method[] getDeclaredFields() //得到该类所有方法,不包含父类,包含private
Constructor[] getConstructors() //所有public 构造函数
Constructor[] getDeclaredConstructors[] //所有构造函数,包含private
Object newInstance(); //创建这个类的一个新实例,调用该类默认的无餐构造器.
Class getComponentType();//得到一个数组的Class对象.
Constructor|Field|Method
int getModifiers() //得到修饰符 public|private
String getName()//得到名字
Class[] getParametersTypes() //得到形参的类型
Class getReturnType() //得到返回类型(Method 类)
Class getDeclaringClass() //得到该对象的Class 对象.
Object newInstance(); (Constructor)//创建这个构造器所属类的一个新实例
Object invoke(Object obj,Object[] param);//Method调用这个方法执行自己, obj为method执行的类,param是该方法的参数,静态方法的obj 传null
Field
Object get(Object obj) ;//得到obj对象的field成员变量的值
void set(Object obj,Object new Value);//用 newValue 设置Obj对象中用Field对象表示的成员
AccessibleObject
void setAccessible (boolean flag) //true标识使对象的私有属性也可以被查询和设置
boolean isAccessible() //返回反射对象是否可被访问.
-
接口的方法自动标记为pulbic,常量标记为public static final
-
Clone
1.当复制一个变量时.原是变量和复制变量指向同一个对象.此时两个变量指向同一个对象.
2.使用clone,则会新创建一个对象,与原对象的值一样. 但是clone是一种浅拷贝,原来对象内部的子对象并没有被克隆.所以到账两个对象都持有子对象的引用.例如 a 克隆自 b, b中有个引用c,克隆后,a中的c引用和b中的c引用指向同一个对象.
3.为了让子对象也被克隆, 需要所有需要克隆的类实现Cloneable接口,并重写public clone方法(Object的方法),
4.所有数组都有一个clone方法. -
内部类
1.内部类可以访问外部类所有数据,包括private.
2.内部类只对外部类显示.对其他类是隐藏的.
3.匿名内部类适合做回调函数.
4.内部类持有一个外部类的引用.编译器会在创建内部类时传入一个外部类的引用
5.局部内部类,定义在方法中的内部类,不能用public,private修饰,他的作用域就是这个方法中,并且只有这个方法可以访问这个类.
6.局部内部类访问方法中的形参时,形参要用final修饰,其实是内部类会得到一个形参的复制.
7.匿名内部类是没有名字的局部内部类,匿名内部类不能有构造器,而是将构造参数传递给匿名内部类的父类的构造函数.
8.static声明的内部类不会持有外部类的引用.声明在接口中的内部类自动为static,public -
代理
1.代理是在运行时创建实现了一组接口的类.
2.创建代理对象,需要使用Proxy.newProxyInstance()方法.该方法需要三个参数,类加载器,接口的Class类的数组,调用处理器 InvocationHandler. -
异常
1.所有异常都继承子Throwable, Error,Exception是它的两个子类,Error属于系统错误,Exception是我们要程序的错误,需要处理.
2.子类覆盖父类的方法.子类抛出的异常要小于父类的异常的范围,
3.方法必须抛出或捕获所有的已检查异常
4.finally语句块无论如何都会执行. -
泛型
1,泛型类,一个泛型类就是具有一个或多个类型变量的类
public class Pair<T,U>{ ...}
2.泛型方法 <T> 标识声明次方法为泛型方法,<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T,没有声明的标识无法在泛型方法中使用
public <T>T getMiddle(T[] a){...}
3.泛型限定public static <T extends Comparable> T add (T a){...} //限制T 是实现了Comparable接口的类或接口 <T extends Bundong Type > 标识 T是绑定类型的子类型,T和绑定类型可是一类,可以是接口. <T extends Comparable & Serializable > //标识T 是同事实现 Comparable和 Serializable
4.类型擦除
虚拟机没有泛型类型对象.编译器会将泛型类型转化为特定的类.擦出类型变量,替换为定义的类型
public class Pair<T>{
public T first;
}
编译器会转化成具体类型.如
publci class Pair {
public Object first;
}
5.泛型的局限性
1. 不能用基本类型实例化类型参数
Pair<int> 不合法, Pair<Integer> 合法
2. 运行时只能查询到原始类型.而不能查到泛型类型
if( a instanceof Pair<String>) <String> 写不写都没意义, 只会判断 a 是不是 Pair类型的子类型
3. 不能抛出也不能捕获泛型类实例
public static <T extends Throwable> void doWork( Calss <T> t) {
try{
dowork...
}catch (T e){ //不合法, 必须写指定的异常类 (Exception e)
...
}
}
4. 参数化类型的数组不合法
Pair<String> talbe =new Pari<String>[10] //不合法
5. 不能实例化类型变量. new T(...) 是不合法的
6. 不能在泛型类中使用静态的泛型变量
public class SingleTon <T>{
public static T instantce; //不合法
}
6.泛型的继承规则
假如 B exentends A
那么Pari<B> 和 Pari<A> 之间不是继承关机,他俩没有任何关系
ArrayList<B> 和 List<B> 是继承关系. 同时 ArrayList<B> 可以转化为 ArrayList 类型
7.通配符类型
Pari< ? extends Employee> 表示 任何泛型类,他的类型参数需要是Employee的子类.
Pari<? super Employee>表示 任何泛型类,他的类型参数要是 Employee的父类.
带有超类型限定的通配符可以像泛型对象写入.带有子类型限定的通配符对象可以从泛型对象读取.
Pari<?> 无线定通配符.
? getFirst<() //只能赋值给一个Object
void setFirst(?) //任何对象都不能调用这个方法,因为无法确认接受什么样的形参
-
集合
1.队列通常有两种实现方式.1是使用循环数组,他的容量有限.2是使用链表,容量无限.
2.对于实现Iterable接口的类,都可以使用foreach循环.
3.集合类的 基本接口public interface Collection<E>{ boolean add(E element); Iterator<E> iterator(); ... } public interfacte Interator<E>{ E next(): boolean hasNext(); void remove(); }
4.应该将java迭代器认为是位于两个元素之间,当调用next时,迭代器就越过并返回下一个元素.
5.迭代器的remove会删除调用next后越过并返回的元素.所以调用remove前需要调用next
6.数组和数组列表的删除和插入元素都需要它之后的元素移动位置,比较消耗时间.
7.ListIterator 接口提供了add,remove方法,用来想链表中添加删除元素.他会把元素添加在迭代器next方法返回的元素之后.
8.链表适合于频繁的增删元素,不适合通过索引找到元素.
9.hashtable,hashtable为每个对象生成一个hash code,他的底层结果是链表数组,数组中每一项都是一个链表,称为桶.
10.通常指定桶的数目为集合元素的0.75~1.5,当hashtable数据超过总容量的某一比例(0.75,也叫填装因子)时,就为hashtable扩容,将桶数*2,然后将原来的元素插入到新表中,废弃原表.HashSet就是采用HashTable的数据结构,元素唯一且无序.TreeSet采用红黑树结构,但是他是有序的集合.元素唯一.
11.如何集合TreeSet中的元素要排序.被排序的类需要实现Comparable接口重写conpareTo方法,或者在集合TreeSet构造时传入Compartor匿名内部类实现conpare比较方法. -
线程
- 进程拥有自己的一整套变量,线程则共享数据.
- 线程被阻断(sleep或wait)后,调用interrupt方法会抛出InterruptedException.
- 调用 interrupt时.会将线程的中断标记为设置为true,线程自己决定如何响应中断.
- 线程的六种状态. new(新生),Runnable(可运行),Bolcked(被阻塞) Waiting(等待) Timed waiting(计时等待)
Terminated(被终止).
1当创建一个新线程时,处于new 状态.还没开始运行代码
2调用start后,线程出于runnable状态.这个线程可能在运行也可能不再运行,取决于操作系统给线程提供的运行时间.
3当线程出于被阻塞或者等待状态时,他暂时不活动,不运行任何代码且消耗最少的资源.
当一个线程A试图获取一个内部的对象锁,但锁被其他线程持有时,A进入阻塞状态.其他线程释放锁,A变成非阻塞状态
当线程A等待另一个线程通知调度器一个条件时,A进入等待状态.
有几个方法有个超时参数,调用他们导致线程A进入计时等待状态,知道超时期满或者接收到适当的通知,其中的方法有 Thread.sleep. Object.wait. Thread.join. Lock.tryLock. Condition.await
4线程的终止状态
run方法正常退出而自然死亡
以为一个没被捕获的异常导致run方法终止而意外死亡 - 线程的属性.
优先级.MIN_PRIORITY(1)-MAX_PRIORITY(10),线程继承他父类的优先级.调度器总是会先选择优先级高的线程进入活动状态.
守护线程.为其他线程 提供服务.当虚拟机只剩下守护线程时,虚拟机就退出了.
异常处理器Thread.UncaughExceptionHandler用来得到未捕获异常. - 线程锁
1.多个线程同时访问一个数据时,容易造成数据错乱.叫竞争条件.
2.synchronized关键字和ReentrantLock.lock() ReentrantLock.unlock(),方法用来枷锁,保证某一对象在一个时间只能被一个线程A访问,其他的线程B要访问时,会被阻塞,直到A把锁释放.
3.条件对象.用来管理已经获得了锁缺因为缺乏条件而不能工作的线程.
public void transfer(int count){
banl.lock();
while(count <0){
wait//此时需要等待.但是该线程A已经拿到了锁.即时等待.别的线程B也无法拿到锁修改count数据
//所以应该调用 condition.await(); 此时线程A被阻塞,并释放锁,线程B可以修改count ,然后调用同一个 condition对象的 signaAll();激活A线程,A从await()处继续执行
//Adiaoyong await后,进入该条件的等待集.只有signaAll被调用后,才从等待集中移除,等待调度器的激活.
}
//do something
finally{
banl.unlock();
}
}
//调用signalAll不会立即激活一个等待线程,它仅仅接触等待线程的阻塞,以便这些线程可以在当前线程退出同步方法后,用过竞争实现对对象的访问.
4.内部对象锁 synchronized .内部对象锁将使方法同时只有一个线程可以访问,并且内部对象锁只有一个条件对象.wait = Condition.await() notify =Condition.signlAll()
5.synchronized方法也可以修饰镜头方法.此时,该方法获得类对象的内部锁.例如A类的静态方法会拿到A.class的对象锁.
6.Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
Volatile变量不能提供原子性.
- 死锁. 指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象.
- 读写锁
ReentrantReadWriteLock.readLock();得到一个读锁,但排斥所有写操作
ReentrantReadWriteLock.writeLock();得到一个写锁.排斥所有其他读操作和写操作 - 阻塞队列.生产者线程向队列插入元素,消费者线程从队列中取出元素.当队列为空时消费者线程阻塞,当队列已满时生产者线程阻塞.
常用的阻塞队列. LinkedBlockingQueue 容量没上限,但可以指定.ArrayBlockingQueue 需要指定容量,可选择是否需要公平性,若设置公平性.则等着最长时间的线程会优先处理.PriorityBlockingQueue 带有优先级的队列,元素按照优先级顺序被移出.容量无上限. - 支持并发的集合
ConcurrentHashMap,ConcurrnetSkipListMap,concurrentSkipListSet,ConcurrentLinkedQueue.
使用Collections.synchronizedList(new ArrayList<V>())
Collections.synchronizedMap(new HashMap<K,V>)来把线程不安全的集合转化为线程安全的集合. - Callable与Future
Runnable是一个没参数和返回值的异步方法.而Callable是有返回值的异步方法.
Future 保存异步计算的结果.
FutureTask是一个包装类,可讲Callable 转化为Future和Runnable.他实现了二者的接口
FutureTask<Integer> task =new FutureTask<Integer>(new Callable<Integet>(){
publci Integer call(){ ...}
})
new Thread(task).start();
int result =task.get(); - 线程池.线程池准备许多线程,将Runnable交给线程池后,就有线程调用run方法.当run方法推出后线程不会死亡.线程池通过submit,方法提交任务到线程池,通过shutdown结束所有的线程.
网友评论