a.面向过程
a1. 数值类型空间占用:
byte 1B 2的8次方 -128到127
short 2B 2的16次方 -32768到32767
int 4B 2的32次方 -2147483648到2147483647
long 8B 2的64次方 -2的63次方 到 2的63次方-1
float 4B -->1.3f
double 8B -->1.3d
char 2B '\u' 代表十六进制Unicode码值 97 <=> a <=> '\u0061'
a2. 两个byte类型的变量运算结果为int类型,因为CPU中寄存器的存储空间为4字节,需要强制类型转换
a3. 在java中0和1不能代表真和假
a4. 字符串运算(A)
'a' + 'b' + 'c' 表示相加
"a" + "b" + "c" 表示相连
a5. 字符串运算(B)
"1" + 2 + 3 结果为 123
1 + 2 + "3" 结果为 33
a6. 局部变量
- b1. 必须先赋值后使用
- b2. 作用范围是定义它到定义它的代码块结束
- b3. 重合范围内不允许两个局部变量命名冲突
a7. 表达式一定有值
a8. 数组:一次定义多个变量,并且在内存中分配多个连续的存储空间
-
b1. 数组在分配空间后,初始化默认值为0
int[] a = new int[5]; int[] a = {100, 90 , 80, 70 , 85}; int[] a = new int[]{100, 90 , 80, 70 , 85};
-
b2. 二维数组
-
c1. int[][] a = new int[3][4]; --> a.length = 3; //表示a的行数
图例---> {89, 90, 70, 60} {89, 90, 70, 60} {89, 90, 70, 60}
-
c2. 还可以分开定义二维数组
int[][] a = new int[3][]; a[0] = new int[3]; a[1] = new int[4]; a[2] = new int[2];
-
c3. 一次性定义二维数组并赋值
int[][] a = {{1,2,4}, {3,4,5,6}, {5,9,8,7,3}};
-
-
b3. java.util.Arrays.sort(a); //为数组a从小到大排序
b. 面向对象
b1. 编程思想:如何把一个问题细化成每一个可行的步骤
- c1. 符合思维习惯
- c2. 各司其职,各尽所能
- c3. 弱耦合性
- c4. 可重用性
- c5. 可扩展性
b2. 面向对象的设计原则
- c1. 单一职责原则 --> 一个类,最好只做一件事,只有一个原因引起它的变化
- c2. 开放封闭原则 --> 对扩展开放,对修改封闭
- c3. 依赖倒置原则 --> 依赖于抽象,就是对接口编程,不要对实现编程
- c4. 接口隔离原则 --> 使用多个小的专门的接口,而不要使用一个大的总接口
- c5. Liskov替换原则 --> 子类必须能够替换其基类
b3. 类 – > 对象的抽象,是客观事物(对象)在人脑中的主观反映
b4. 实例变量 --> 在类的内部定义的非静态属性
- c1. 不要求先赋值后使用
- c2. 访问范围至少为本对象的内部
- c3. 当实例变量与局部变量发生命名冲突的时候局部变量优先
b5. 方法的声明
-
c1. 修饰符
-
c2. 参数表
-
c3. 返回值
-
c4. 方法名
-
c5. 抛出的异常
注: 在java中如果有多个修饰符,顺序可以互换,如下: static public void main(String[] args){}
b6. 方法重载 --> 方法名相同,参数表不同 (编译的时候识别重载)
b7. 构造方法
- c1. 无返回类型
- c2. 系统默认提供一个无参的构造方法,前提是我们没有手写任何构造方法
- c3. 在对象构造时自动调用一次
- c4. 方法名必须和类名相同
b8. 对象内存结构
- c1. 堆内存 --> 只包含成员变量
- c2. 栈内存 --> 局部变量(对象类型存对象引用,即堆内存地址)
- c3. 常量池 --> 静态变量或常量
- c4. 方法区 --> 对象的方法(即使new出多个对象也只存在一个方法)
b9. java中创建对象的方法
- c1. new
- c2. clone()
- c3. 对象序列化
- c4. 反射
b10. 深克隆和浅克隆
-
c1. 浅拷贝 --> 拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象
实现方法: d1. 实现Cloneable接口 d2. 重写clone()方法 public Object clone(){ return super.clone(); }
-
c2. 深拷贝 --> 不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象
实现方法: d1. 实现Cloneable接口 d2. 重写clone()方法 public Object clone(){ //将引用的对象也拷贝一份并重新赋值 } 注:用序列化与反序列化的方式也可以实现深拷贝
b11. 关键字this表示当前对象,this()用来在有参的构造方法中调用无参的构造方法,而且为构造方法的第一个语句
b12. java方法参数传递规则 --> 简单类型传值,对象类型传引用
b13. String变量存储空间
-
c1. String是不可变类,不可以被继承并且值不会发生改变
--> 源码定义 private final char value[];
-
c2. JVM维护了一个字符串常量池,每当创建字符串变量时,JVM首先检查字符串常量池,如果常量池中已经存在,则返回池中的字符串对象引用,否则创建该字符串对象并放入池中
String a = "abc";//这种方式会放入常量池中
-
c3. 当使用new String(String str)方式等创建字符串对象时,不管字符串常量池中是否有与此相同内容的字符串,都会在堆内存中创建新的字符串对象
-
c4. intern()方法返回字符串对象在字符串常量池中的对象引用,若字符串常量池中尚未有此字符串,则创建一新的字符串常量放置于池中。
System.out.println(a == a.intern());
-
c5. 字符串比较:
- d1. if(a == b) //比较的是字符串的引用地址
- d2. int value = s.compareTo(s1);//依次比较每个字符的字符编码
- d3. boolean b = s.equals(s1);//判断两个字符串对象的内容是否相同
b14. 继承 --> 父类是子类共性的抽象
- c1. 子类只能继承一个父类,单继承是为了满足树状关系的简单性
- c2. 覆盖
- d1. 父类和子类的方法名、返回值、参数表都相同叫做覆盖
- d2. 子类方法的修饰符一定要等于或者宽于父类方法的权限
- d3. 子类继承了父类中的方法定义,用自己的特殊实现替换掉父类提供给他的一般实现
- d4. 覆盖只存在于方法之间,属性定义相同叫遮盖
- c3. 父类和子类之间也可以出现重载
- c4. 构造一个子类对象时一定会先构造它的父类对象,父类对象会成为子类对象的一部分
- c5. 父类的私有属性和方法都可以继承到子类,只是子类无法访问,因此也可以说父类的私有属性和方法不可以继承到子类
b15. 访问权限规则:
访问修饰符 | 访问范围 | 继承关系 |
---|---|---|
private | 只有本类内部可以访问 | 不能继承 |
default | 本类加本包可以访问 | 同包可以继承 |
protected | 本类+本包+不同包的子类 | 可以 |
public | 公开 | 可以 |
b16. 对象的构造过程
- c1. 无继承关系
- d1. 分配空间(把所有属性赋值null或0)
- d2. 初始化属性(不包括类变量)
- d3. 调用一个构造方法
- c2. 有继承关系
- d1. 分配空间(子类和父类都分配空间)
- d2. 递归的构造父类对象
- d3. 初始化本类属性
- d4. 调用本类的构造方法
b17. super -->指向父类对象,往往用于在子类中访问父类被遮盖的属性或者被覆盖的方法
- c1. super(s)调用父类带参数的构造方法
- c2. super(s)写在子类构造方法的第一行
b18. 多态 --> 编译时类型(父类)与运行时类型(子类)不同
-
c1. 子类对象可以当作父类对象,这是多态的本质
-
c2.
Animal a = new Dog(); Dog d = (Dog)a;//必须强制类型转换,否则编译出错
-
c3. 多态的特点:
- d1. 对象运行时类型永远不变
- d2. 只能调用其编译时类型中定义的方法(强转后则可调用子类的特殊方法)
- d3. 运行时会根据运行时类型去找覆盖后的方法
-
c4. dog instanceof Animal ;//如果对象是这个类或者其子类则返回true
-
c5. 多态的作用 --> 把子类当父类对象来看,可以屏蔽不同子类的差异
-
c6.
public A method(B b){};
- d1. method方法允许以B对象或B的子类对象为参数
- d2. 也允许以A对象或者A对象的子类为返回值
b19. static --> 全类公有(本类中所有对象公用一个空间)
-
c1. 能修饰属性、方法、初始化代码块、内部类
-
c2. 修饰变量
public int a;//实例变量 public static int b;//类变量,访问b也可以 A.b 即 类名.类变量
-
c3. 修饰方法
public static void print(){};//静态方法,访问print也可以 A.print() 即 类名.类方法
-
c4. 静态属性的存在与否与对象无关
-
c5. 静态代码块
static{ };//静态代码块 --> 当类被加载时{}中的内容会被执行一次,只一次,因为类的加载只有一次
-
c6. 注意
- d1. 在静态方法中不允许访问类的非静态成员,也不允许出现this
- d2. 静态方法只能覆盖静态方法,但是不会出现多态性
b20. 类加载
此过程要先于对象构造,当JVM第一次使用一个类的时候,会通过ClassPath找到对象的.Class文件,把文件内容读入JVM并保存起来。类加载的最终产品是位于堆区中的Class对象,该Class对象封装了类在方法区内的数据结构
-
c1. 类加载的过程
- d1. 装载:查找和导入Class文件;
- d2. 链接:把类的二进制数据合并到JRE中;
- e1. 校验:检查载入Class文件数据的正确性;
- e2. 准备:给类的静态变量分配存储空间(赋默认值);
- e3. 解析:将符号引用转成直接引用;
- d3. 初始化:对类的静态变量(赋值),静态代码块执行初始化操作
-
c2. 类加载器 --> 双亲委派模型(自下而上检查,自上而下加载)
- d1. Bootstrap ClassLoader --> 加载$JAVA_HOME中jre/lib/rt.ar里所有的class,由C++实现,不是ClassLoader子类
- d2. Extension ClassLoader --> 加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包
- d3. App ClassLoader --> 加载classpath中指定的jar包及目录中class
- d4. Custom ClassLoader --> 应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都自行实现了ClassLoader
b21. final --> 能修饰变量(局部变量、类变量、成员变量)、方法、类
- c1. 修饰变量时: 变量变常量(赋值后不可以更改)
- c2. 修饰属性时: 赋值只有两个机会 --> 1. 初始化属性时赋值 2. 构造方法中赋值
- c3. 修饰方法时: 该方法不能被子类覆盖(用以保证操作的稳定性)
- c4. 修饰类时: 该类不能被继承(注意: ;一个final类中的所有方法默认都是final的)
b22. abstract --> 能修饰类和方法
-
c1. 修饰类 时: 该抽象类不能构造对象(是用来被子类继承的)
-
c2. 修饰方法时: 称为抽象方法(只有方法定义,没有方法实现)
-
c3. 如果一个类有抽象方法,这个类必须为抽象类(不然实例化之后调用不动这个抽象方法)
-
c4. 单一个抽象类可以没有任何抽象方法
-
c5. 子类在继承抽象类时,必须实现该抽象类的每一个抽象方法(不然实例化后有些抽象方法调不动)
-
c6. 多态往往应用于抽象类中
-
c7. 举例:
public abstract class super{ public abstract void method();//这里无大括号 }
-
c8. 抽象类中可以写构造方法,作用是被子类的构造方法调用
-
c9. 非法的修饰符组合
- d1. abstract 与 final -->继承与非继承互斥
- d2. abstract 与 static -->继承的无静态多态性
- d3. abstract 与 private -->私有的属性和方法无法被继承
注意: 构造方法不存在继承,构造方法也不能被 abstract、final、static修饰
b23. interface --> 本质上它就是一个抽象类
-
c1. 一个文件只能写一个公开接口,接口名与文件名相同
-
c2. 接口是一种特殊的抽象类,所有属性都是公开静态常量,所有方法都是公开抽象方法,不允许定义构造方法
-
c3. 因为所有属性都是公开静态常量,所以public static final 可以省略
-
c4. 因为所有方法都是公开抽象方法,所以public abstract 可以省略
-
c5. 虽然接口的public是默认的,但实现类必须加上public
-
c6. 我们可以用关键字implements实现一个接口
-
c7. 接口实例:
interface Ia{ public static final int A = 10; public static final String S = "abc"; public abstract void method1(); public abstract int method2(); }
-
c8. 用类实现接口,就要实现接口中定义的所有方法。而接口可以声明一个对象的引用,该引用可以调用编译时类型中定义的方法。
-
c9. 接口间也存在继承,关键字extends,而且允许多继承,用","隔开
interface IC extends IA,IB{}
-
c10. 一个类在继承另外一个类的同时,还可以实现多个接口,实现了子接口就相当于实现了父接口
public class Dog extends Animal implements IA, IB{}
-
c11. 接口的作用:
- d1. 实现多继承(对同类事物的共性做一个再抽象,通过接口实现的多继承不会破坏类之间树状关系的简单性)
- d2. 标准(一个接口是一个标准,可以把标准的制定者,标准的使用者和标准的实现者分离开。用以实现使用者和实现者的弱耦合,接口是java中最重要的解耦合工具)
- d3. 通过接口可以屏蔽不同实现类的差异,把接口的一个实现替换成另外一个实现的时候,对上层代码在结构上没有影响
- d4. 增加了程序的可扩展性
-
c12. 接口回调 --> 先有接口的使用者,后有接口的实现者,把实现者传给使用者,使用者通过接口调用实现者方法
b24. 如果一个类不写extends什么,那么将被默认为Object的直接子类(Object是所有类的父类)
b25. Java垃圾回收机制
本质上就是将不再使用的对象进行回收
jVM收集策略: 最少收集(万不得已才收集)
-
c1. 哪些对象不再使用? --> 不再被引用的对象(判定方法如下)
- 老方法 --> 引用计数器: 维护一张列表,多一个引用加一,少一个引用减一,结果为0的收集
- 新方法 --> 跟踪收集器: 对象引用递归遍历,找不到引用的就收集
-
c2. 如何回收?
算法很多: 1.标记清除算法 2.复制算法 3.分代收集算法(G1在用)
收集器种类很多, JDK1.7开始用G1收集器(多线程并且能充分利用多CPU、多核环境)- d1. 本质上就是分代收集
- d2. 内存结构如下:
- 持久代: 被JVM来存放方法区,而方法区存放了类信息、静态变量、常量、和方法信息。对持久代的回收 --> 废弃常量和无用的类
- 年老代:
- 内存是新生代的2倍
- 经历了N次垃圾回收后仍然存活的对象
- 内存满时触发Full GC
- 新生代:
- 大部分对象在Eden区生成
- Minor GC 过程(注:下面移动的都是标记为存活的对象):
n1. 将eden区对象复制到survivor0区,然后清空eden区
n2. 当survivor0区也存放满了时,将eden区和survivor0区存活对象复制到survivor1区,然后清空eden区和survivor0区
n3. 此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复
n4. 当survivor1区不足以存放eden和survivor0的存活对象时,就将survivor1区存活对象直接存放到老年代
-
c3. finalize() --> 在对象垃圾回收时调用finalize方法 (Object类下)
-
c4. System.gc() --> 唤起垃圾收集
b26. Hashset、Hashmap、Hashtable与hashcode()和equals()的密切关系
-
c1. equals()和hashcode()必须遵循的规则:
- d1. equals()相等的两个对象必须hashcode()也相等
- d2. 如果两个对象的hashCode相等,它们并不一定equals()相等
根据如上规则最终推导出如下结论:
- e1. hashcode()不等,一定能推出equals()也不等
- e2. hashcode()相等,equals()可能相等,也可能不等
-
c2. Hash类集合的特点是,不允许出现重复对象。(如何做到?)
- d1. 判断两个对象的hashCode是否相等,如果不相等,认为两个对象也不相等,如果相等,转入d2
- d2. 判断两个对象用equals运算是否相等如果不相等,认为两个对象也不相等如果相等,认为两个对象相等
-
c3. Object默认的equals()比较的是对象地址,默认的hashCode()返回的也是对象地址
b27. 内部类(成员内部类、静态内部类、局部内部类、匿名内部类)
内部类的作用:
- 不破坏封装的情况下访问另外一个类的私有成员
- 把接口公开,但是把接口的实现类作为内部类隐藏起来,强制弱耦合
- 接口+内部类才可以实现多继承
- c1.成员内部类
-
d1. 可以访问外部类的私有成员变量
-
d2. 构造成员内部类对象必须先构造外部类对象,通过外部类对象.new构造内部类对象
-
d3. 成员内部类不能是静态成员
public class MemberOuter { private int num = 3; private String name = "somchai"; public class Inner{ String myInner = "myInner"; String innerMethod(){ name = "inner hehe"; return name; } } public static void main(String[] args) { MemberOuter outer = new MemberOuter(); Inner inner = outer.new Inner(); System.out.println(inner.innerMethod()); } }
-
- c2. 静态内部类
-
d1. 只能访问外部类的静态成员(包括私有)
-
d2. 构造静态内部类对象,可以直接构造不需要外部类对象
public class StaticOuter { private static String outName = "abc"; public static class Inner{ public void runTime(){ System.out.println(outName); } } public static void main(String[] args) { StaticOuter.Inner inner = new StaticOuter.Inner(); inner.runTime(); } }
-
- c3. 局部内部类
-
d1. 定义在方法内部,有效范围和局部变量相同(代码块内部)
-
d2. 不仅可以访问外部类的私有属性,而且可以访问外部类的局部变量,但是要求被访问的局部变量是final的
public class PartOuter { public static Runnable getMe(){ final int a = 10; class PartInner implements Runnable{ @Override public void run() { System.out.println("**********runOver***********" + a ); } } return new PartInner(); } public static void main(String[] args) { new Thread(PartOuter.getMe()).start(); } }
-
- c4. 匿名内部
-
d1. 它是一个特殊的局部内部类,定义这个类的目的是继承某一个类或者实现某一个接口
-
d2. 用一个隐含的没有名字的类继承一个类或者实现一个接口,同时构造出一个对象
-
d3. 匿名内部类无法定义构造方法
public class NoNameOuter2 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("*****run no name class*****"); } }).start(); } }
-
b28. 无穷大
1.0/0 不会有异常,因为结果为double,double有一个常量Infinity代表无穷大,-Infinity代表无穷小
b29. 异常
- c1. RuntimeException(不可查异常)
- 这些异常一般是由程序逻辑错误引起的,应该从逻辑角度尽可能避免
- 可以不处理(交给JVM处理)
- 比如 NullPointerException
- c2. 非RuntimeException(可查异常)
- 无法避免的异常(一定会发生)
- 必须处理(try块或throws)
- 比如 IOException、SQLException以及用户自定义的Exception
- c3. return语句先执行,finally语句后执行,return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行finally语句后才真正开始返回。
- c4. 子类的覆盖方法不能比父类的被覆盖方法抛出更多的异常