一、关键词final
(1)四种用法
修饰类(该类不能被继承,没有子类)
修饰成员方法(该方法不能被重写)
修饰成员变量 (因为成员变量有默认值,所以在申明成员变量时直接赋值,或者在所有构造函数中赋值,两者选其一)
修饰局部变量 (赋值一次,终身不能改变)
注:final修饰引用类型,变量地址值不能变,但是指向的对象属性可以改变
(2)final,finally,finalize三者之间的区别
final是java的关键字,修饰符,表示不可变。
finally是java异常处理模型的最佳补充,finally结构使代码总会执行,而不管无异常发生。
finalize 使用这个方法在垃圾收集器将对象从内从中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个 对象没被引用时对这个对象调用的。他是Object类中定义的。因此所有的类都继承了它。
二、基本数据结构
byte字节型 | 1个字节 |
short短整型 | 2个字节 |
char字符型 | 2个字节 |
int整型 | 4个字节 |
float浮点型 | 4个字节 |
long长整型 | 8个字节 |
double双精度浮点型 | 8个字节 |
boolean布尔类型 | 1个字节 |
三、 java面向对象的三大特性
(1) 封装,继承,多态
继承是多态的基础,多态就是基类的引用指向子类的实现。
(2)继承
- 子类构造方法当中有一个默认隐含的super()调用,所以一定是先调用父类构造函数,后执行子类构造函数。
如果父类中自定义了构造函数,所以系统不提供无参构造函数,子类构造函数需要手动super调用父类有参构造函数,
super第一位执行,并且执行一次
public class Person {
public Person(String name) {
Log.d("aaa", "父类构造函数");
}
}
public class Student extends Person{
public Student() {
super("");
Log.d("aaa", "子类构造函数");
}
}
- 单继承,但是可以多级继承
如果多个父类有相同的方法,子类不知选择执行哪个方法
(3)多态
- 成员变量的访问
看等号左边是谁,优先用谁,没有则向上找
Fu fu=new Zi();
fu.num; //打印父类的num值
- 成员方法的访问
看等号右边是谁,优先用谁,没有则向上找
public class Person {
public int age = 10;
public void action() {
Log.d("aaa", "父类方法");
}
}
public class Student extends Person {
public int age = 20;
public void action() {
Log.d("aaa", "子类方法");
}
}
Person person = new Student();
Log.d("aaa", "" + person.age);
person.action();
//结果
10
子类方法
(4)重写override和重载overload的区别
- 重写:发生在继承,方法名,参数都要和父类一致;
返回值要求子类类型小于等于父类类型,如父返回string,子可以同样返回string,不能返回object
权限修饰符:子类的修饰符大于等于父类的,以便在外部通过父类的引用可以调用子类的方法。
抛出的异常:子类抛出的异常要与父类抛出的异常一致或者父类异常的子类,这应该是与向上转型有关
- 重载:发生在同一类之间,方法名一致,方法参数必须不一致(个数,类型,参数),其他的都可以修改。
注:参数都一样,只有返回类型不同,这不是重载。
参数和返回类型都不同,这个是重载。
四、抽象类
- 抽象方法
加上abstract关键字,去掉大括号,没有方法体
抽象方法所在的类,必须是抽象类
- 抽象类
用abstract关键字修饰类
不能直接new创建抽象类对象,但是可以有构造方法,是供子类创建对象时,初始化父类成员使用的
子类继承父类,子类必须覆盖重写父类的所有抽象方法,除非子类也是抽象类。
抽象类不一定有抽象方法,但是有抽象方法的类必是抽象类
五、接口 interface
- 接口的内容包含
如果是Java 7,那么接口中可以包含的内容有:
常量 public static final 数据类型 常量名称=数据值;
抽象方法 public abstract 返回值类型 方法名称(参数列表);修饰符必须是固定的关键字:public abstract,可以省略 不写
如果是Java 8,那么接口中可以包含的内容有:
默认方法 public default 返回值类型 方法名称(参数列表){方法体};public 可以省略,但不能改变
静态方法 public static 返回值类型 方法名称(参数列表){方法体};public 可以省略,但不能改变
如果是Java 9,还可以额外包含有:
私有方法 普通私有方法 解决多个默认方法之间重复代码问题 private 返回值类型 方法名称(参数列表){方法体}
静态私有方法 解决多个静态方法之间重复代码问题 private static 返回值类型 方法名称(参数列表) {方 法体}
接口不能包含静态代码块,也不能包含构造函数
- 接口之间继承extends,并且可以多继承
public interface InterfaceA extends InterfaceB,InterfaceC{
}
六、java权限修饰符
- public 用public修饰的类,类属变量及方法,包内及保外的任何类(包括子类和普通类)均可以访问
- protected 用protected修饰的类,类属变量及方法,包内的任何类及包外那些继承了该类的子类才能访问,重点突出继承
- defalut 如果一个类,类属变量及方法没有用任何修饰符,包内的任何类(包括此类的子类)都可以访问它,而对于包外的任 何类都不能访问它(包含包外继承了此类的子类),重点突出包;
- private 只有本类可以访问,而保内包外的任何类均不能访问。
七、内部类
(1)成员内部类
1、成员内部类使用外部类,随意使用;外部类使用内部类,需要借助内部类对象
2、外部类名称.内部类名称 对象名=new 外部类名称().new 内部类名称();
Body.Heart heart=new Body().new Heart();
3、访问同名变量
public class Outer{
int num=10;
public class Inner{
int num=20;
public void methodInner(){
int num=30;
System.out.println(num);//局部变量
System.out.println(this.num);//内部类的成员变量
System.out.println(Outer.this.num);//外部类的成员变量
}
}
}
(2)局部内部类
在方法中定义内部类
(3)匿名内部类
八、static静态
- static变量
静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量时对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
注:非静态方法可以使用静态变量
- static方法
静态方法,由于静态方法不依赖任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。
注:在静态方法中不能访问类的非静态成员变量和非静态成员方法。
在非静态成员方法以及静态成员方法中可以访问静态成员方法和变量
- static代码块
用来形成静态代码块以优化程序性能,static块可以置于类中的任何地方,类中可以有多个static块,在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
注:静态代码块不能访问非静态方法和非静态成员变量。
静态代码块能访问静态方法和静态成员变量。
九、类初始化顺序
public class Person {
Teacher teacher = new Teacher("父类");
static {
Log.d("aaa", "父类static");
}
{
Log.d("aaa", "父类构造代码块");
}
public Person() {
Log.d("aaa", "父类构造函数");
}
public static void main(String[] args) {
new Student();
}
}
public class Student extends Person{
Teacher teacher=new Teacher("子类");
static {
Log.d("aaa", "子类static");
}
{
Log.d("aaa", "子类构造代码块");
}
public Student() {
Log.d("aaa", "子类构造函数");
}
}
public class Teacher {
static {
Log.d("aaa", "参数类static");
}
{
Log.d("aaa", "参数类构造代码块");
}
public Teacher(String name) {
Log.d("aaa", "参数类构造函数___"+name);
}
}
输出:
父类static
子类static
参数类static
参数类构造代码块
参数类构造函数___父类
父类构造代码块
父类构造函数
参数类构造代码块
参数类构造函数___子类
子类构造代码块
子类构造函数
类加载顺序,如果有父类,需要先加载父类,执行父类的静态代码块,执行子类静态代码块,静态代码块只会运行一次
类初始化顺序,如果有父类,先初始化父类静态变量,成员变量,构造代码块,构造方法,然后子类静态变量,成员变量,构造代码块,构造方法
十、强引用,软引用,弱引用,虚引用
- 强引用
只要引用存在,垃圾回收期就永远不会回收 Obiect obj=new Obiect();
- 软引用
非必须引用,内存溢出之前进行回收
Object obj=new Object();
SoftReference<Object> sf=new SoftReference<Object>(obj);
obj=null;
sf.get();//有时返回null
- 弱引用
第二次垃圾回收时回收
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
wf.get();//有时候会返回null
wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾
弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记
- 虚引用
垃圾回收时回收,无法通过引用对象值,只能通过如下代码实现。
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj=null;
pf.get();//永远返回null
pf.isEnQueued();//返回是否从内存中已经删除
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
虚引用主要用于检测对象是否已经从内存中删除。
十一、java之深拷贝浅拷贝
https://www.cnblogs.com/dolphin0520/p/3700693.html
https://blog.youkuaiyun.com/u014727260/article/details/55003402
十二、泛型
当我们不确定数据类型的时候,可以使用泛型
- 定义和使用含有泛型的类
访问修饰符 class 类名<E>
public class Person<E>{
private E name;
public booelan add(E e){}
public E get(){}
}
- 定义含有泛型的方法,泛型定义在方法的修饰符和返回值类型之间
访问修饰符 <E> 返回值 方法名(参数列表(使用泛型)){
方法体
}
public <E> void method(E e){
System.out.println(e);
}
- 含有泛型的接口
public interface InterPerson<E>{
public abstract void getName(E e);
}
- 4、泛型通配符
十三、java常用API
- API之Scanner
Scanner sc=new Scanner(SYstem.in);//键盘录入
int num=sc.nextInt();
String str=sc.next();
- API之Random
Random r=new Rondom();
int num=r.nextInt();//随机int数字,正负两种
int num=r.nextInt(10);左闭右开 [0-10}
- Math
Math.sqrt(16) //计算平方根4.0
Math.pow(3,2) //计算3的2次方
Math.max(a,b) //a和b的最大值
Math.min(a,b) //a和b的最小值
Math.abs(a) //a的绝对值
Math.ceil(a) //a的天花板,返回大的值
Math.floor(a) //a的地板,返回小的值
Math.random() //[0.0,1.0)
Math.round(a) //四舍五入 float时返回int值,double时返回long值
十四、字符串
字符串的内容永不可变,所以字符串是可以共享使用的。
字符串效果上相当于char[]字符数组,但是底层原理是byte[]字节数组
String str="abc";
String str=new String("abc");
String str=new String(new char[]{'a','b','c'});
- 字符串的常量池
程序中直接写上双引号的字符串,就在字符串常量池中。
String str1="helloworld";
String str2="hello"+"world";
String str3="hello";
String str4=str3+"world";
String str5=new String("helloworld");
System.out.println(str1==str2); //true
System.out.println(str1==str4); //false
System.out.println(str1==str5); //false
- 字符串的format
//formatStr输出为"小李今年30岁"
String formatStr2=String.format(Locale.ENGLISH,"%s今年%d岁","小李",30)
String formatStr=String.foramt("%s今年%d岁","小李",30)
//补齐空格并右对齐
String.format("%10s,world","hello") 输出" hello,world"
String.format("%8d",123) 输出" 123"
String.format("%03d",1) 输出"001"
//补齐空格左对齐
String.format("%-10s, world", "Hello") 输出"hello ,world"
String.format("%-8d", 123); 输出"123 "
//输出最多N个字符
String.format("%.5s", "Hello, world"); 输出"hello"
String.format("%.5s...", "Hello, world"); 输出 "Hello..."
String.format("%10.5s...", "Hello, world"); 输出 " Hello..."
//输出逗号分割数字
String.format("%,d", 1234567); 输出 "1,234,567"
解析:参数一为指定语言环境,可以省略,表示使用本地语言环境
参数二是格式串,后面的参数都是格式串的参数,用于替换格式串的占位符。
占位符以''%x"的形式表示,不同的参数类型要用不同的字母
返回值类型为字符创,也就是格式化的结果。
占位符类型(不区分大小写)
字母 | 适用参数类型 | 说明 |
%s | 字符串类型 | 对字符串进行格式化输出 "ss" |
%c | 字符类型 | 字符 ‘m’ |
%d | 整数(十进制) | 对整数进行格式化输出 123 |
%x | 整数(十六进制) | 以16进制输出整数 FF |
%o | 整数(八进制) | 以8进制输出整数 77 |
%f | 浮点数 | 对浮点数进行格式化输出 99.99 |
%a | 十六进制浮点类型 | 以16进制输出浮点数 FF.35AE |
%e | 浮点数 | 以浮点数进行格式化输出 |
%g | 浮点数 | 以条件来决定是否以科学记数法方式输出浮点数 |
%h | 任意值 | 以 16 进制输出参数的 hashCode() 返回值 |
%b | 任意类型 | 输出为true或false |
%t | 日期时间 | 对日期时间进行格式化输出 |
%n | 无 | 换行符 |
%% | 无 | 百分号本身 |
十五、可变参数
当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
修饰符 返回值类型 方法名(数据类型... 变量名){ }
原理:可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数,参数个数可以为0
public void int add(int... a){
//a[0]
//a.length;
int num=0;
for(int item:a){
num=num+item;
}
}