javaSE知识点一览(1)
JDK=JRE+开发工具包;JRE=JVM+核心类库
main方法作用
- 程序运行入口(没有main方法依然可以编译)
- 被jvm调用
- 可以让类单独调用
- java源文件 程序员编写
- class字节码文件是以二进制形式存储,用来运行
- java--(编译)--.class--(运行)--最后结果
一个文件中可以有多个类,但是只能有一个public类,且该类名和文件名一致;但是一个类中有多个不同类时,就会产生多个.class文件。所以.class文件名应该是:类名+.class 并不一定就是.java文件名
如果在一个Java源文件中定义了1个公共类以及三个普通的类,那么编译该Java源文件会产生_个字节码文件。java是区分大小写的,但是window不区分大小写;一个java文件中,有若干个不区分大小写的“同名”类,在window环境下将会最后只有一个.class文件,编译哪个就产生哪个.class文件。但是会运行java文件中最后一个类的内容,结果也是最后一个类的结果。
java文件中有几个类就有几个.class文件(不准确,一般情况下是这样)
带包编译
javac -d . JavaDemo.java
带包运行
java cn.tedu.demo.Demo
关键字:53个,两个保留字暂时没有用到;都是小写。
标识符:由数字、字母、下划线和$组成;不能使用关键字;大小写敏感;不能数字开头;见名知意。
驼峰命名法:类名每个单词首字母手写;变量名和方法名首个单词首字符小写,后续大写。
常量:运行过程中值不发生改变的量
1.字面值常量
1.字符串常量 "hello" "1"
2.字符常量 'a' '2'
3.整数常量 1 100 1000
4.小数常量 1.0 0.98
5.布尔常量 true、false
6.空常量 null
2.自定义常量。如静态常量
进制:二进制(满二进一、0b或0B开头)、八进制(满八进一、0开头)、十进制(满十进一)、十六进制(满十六进一、0x或0X开头);
进制转换:
变量:运行过程中值发生改变的量。
定义一个变量:数据类型 变量名 变量值;
注意:
先定义后使用;
在哪定义在哪使用;
先赋值后使用;
数据类型:基本数据类型(8个)和引用数据类型
基本数据类型:
数值型:
整数型:
byte:1个字节
short:2个字节
int:4个字节
long:8个字节,以上默认皆为0
小数型:
double8个字节,默认为0.0
float4个字节,默认为0.0
字符型:char4个字节,默认为\u0000
布尔型;boolean,默认为false
引用数据类型:类、接口和数组,默认值皆为null.
运算符:
算数运算:+ - * / % ++ --
关系运算:> < >= <= == !=
赋值运算:= += -= *= /= %= &= |= ^= <<= >>= >>>=
逻辑运算:$ | && || ^ ~
位运算:& | ^ ~ >> << >>>
三元运算:
优先级:() ~ ++ -- ! 算术 << >> >>> 关系 逻辑 & | ^ 三元 赋值
流程控制:
顺序结构:
选择结构:if else/switch-case(switch()的值类型:byte/short/char/int,从JDK1.5开始允许使用枚举,从JDK1.7开始允许使用String)
循环结构:
while:适用于次数不定或者变化不规律的情况
do while:至少执行一次循环体
for:条件明确;次数明确
break:跳出当前层循环,没有下次循环;可用于选择和循环结构
continue:跳出本次循环,下次循环继续;只能用于循环结构
方法:
权限修饰符 返回值类型 方法名(形参列表){方法体;return 返回值}
方法的传参:
对于基本类型的数据,传的是实际类型,被改变后,也不会被影响原来的值;
对于引用类型的数据,传的是地址值,若地址被改变后,会影响原来的对象的值;
方法的递归:循环调用本身;
方法重载:同一个类中,方法名相同,参数列表不同(和其他无关);
方法重写:在继承的基础上,父子类中存在方法签名一致的非静态方法;
子类基本类型返回值=父类基本类型返回值;
子类引用类型方法返回值<=父类引用类型返回值;
子类跑出的异常<=父类跑出的异常;
子类方法权限>=父类方法权限;
如:
如果父类的方法返回值数据类型是引用类型,子类要么和父类一致,要么是其子类,子类可以拿父类的方法或者自己的方法,但是父类不能拿子类的方法。
class A{
public void n(){}
}
class B extends A{
public void m(){}
}
class C{
Public B m(){return null;}
}
class D extends C{
Public A m(){return null;}
}
C c=new D();//向上造型
B b=c.m();//c对象是C类的声明的,就可以去访问C类中的方法,调用完方法返回值是B类,就可以去访问B类中方法
A a=c.m();//方法的具体执行看子类,去调用的是D类中的方法,调用完之后返回A类,就可以去访问A类中的方法---A类中的方法接不住B类中的方法
面向对象和面向过程比较:
面向过程注重事情的每一步流程;面向对象只要拥有对象,就可以调用对象身上的方法;
简单事物优先用面向过程;复杂事物优先使用面向对象;
面向过程是面向对象的基础;
类和对象:
类是对某一类事或物的抽象概括,是不存在的;对象是类的实例化的结果,是真实存在的;
面向对象的特征:
封装:
体现:方法、属性私有化、内部类
作用:提高复用率;保证数据准确性,防篡改
继承:
特征:使用extends关键字;
类与类允许单继承和多重继承;
extends了父类,在加载你当前类前先加载父类,如果没有无参构造又没有调用有参构造是会报错的。
子类不能访问父类什么?私有属性和方法;构造方法和构造代码块;同名成员变量和静态方法(必要时,使用super关键字,否则会发生隐藏,默认访问子类中的);同名非静态方法(必要时,使用super关键字)
多态:
根据时期:
编译时多态--方法的重载;
运行时多态:
向上转型:父类引用指向子类对象,用子类来实例化父类;
向下转型:子类引用指向父类对象,父类强制
Father f = new Son();向上转型
Son son1=(Son)f;向下转型//编译和运行都不会出错
Father f1 = new Father();
Son son2 = (Son)f1;//编译没错,运行出错;子类引用不能指向父类对象
根据形式:
行为多态--方法的重载和方法的重写;
对象多态--向上造型和向下造型;
多态的作用:
使得调用代码形式更灵活和统一;
配合反射实现解耦.
成员变量和局部变量:
成员变量:
定义在类中方法外,作用在整个类中;
堆中或静态常量池中存储,有自己的默认值;
普通成员变量生命周期与对象共存亡;静态成员变量存在于方法区的静态常量池中,与类共存亡;
局部变量
定义在方法/代码块中,只作用在方法/代码块中;
栈中存储,没有默认值;
生命周期仅限于调用方法/代码块时开始,逻辑结束后变量周期也相应结束。
构造方法:
特点:与类同名,没有返回值;
作用:创建对象,初始化属性;
可以写return,规避不合法;
this关键字:代表对当前对象的引用,用于调用非静态变量和非静态方法;
super关键字:
代表当前类的父类对象的应用,用于调用父类的非静态变量和非静态方法以及选择性调用父类的构造方法(因为静态是与类同级的,以上两个关键字都属于对象级别,所以根本调用不到静态方法和属性);
子类构造方法中默认添加父类无参构造方法,如果父类没有无参构造必须手动指定父类有参构造方法;
super语句必须方法在首行;
局部代码块:方法中用{}包裹起来的代码,用来限定变量生命周期以及使用范围,提高栈内存使用率;
构造代码块:类中,创建对象时优于构造方法执行;
静态代码块:与类一同加载,只加载一次;
根本的加载顺序:静态(代码块、属性、方法..)>构造代码块>构造方法
权限修饰符:
public 所有类
private 仅限本类
protected 本类 子类 同包类
默认 本类同包类中
有关静态的知识点:
静态变量:随着类一同加载(所以不能在方法中定义),只加载一次;存放到方法区,属于共享变量;有默认值;
静态方法:随着类加载到方法区;方法区中存储,栈中执行;可以重载;可以继承,但是不可以重写,(因为如果子类出现 了和父类一模一样的静态方法,也是没有任何关系的两个方法,之后父类静态方法会被子类隐藏,如果一个父类型的变量指向子类对象,那么调用的其实还是父类的静态方法。静态方法是类在加载时就被加载到内存中的方法,在整个运行过程中保持不变,因而不能重写。但非静态方法是在对象实例化时才单独申请内存空间,为每一个实例分配独立的运行内存,因而可以重写)如果父子类中存放方法签名一致的方法,要么都是静态方法,要么都是非静态方法;非静态方法可以直接调用静态方法,静态方法不可以直接调用非静态方法,但是可以通过创建对象来:对象.方法/变量名来间接调用。
静态代码块:使用static关键字{}起来;只加载一次;父类静态代码块>子类静态代码块>父类构造代码块>父类构造方法>子类构造代码块>子类构造方法;
final修饰符
final+变量:
对于基本类型,一旦赋值,值就不可变了;对于引用数据类型,指的是地址不变,值可以变;
final+方法:
可以继承,但是不可以重写/隐藏;可以重载;
final+类:
不能被继承;
abstract
抽象类:
没有方法体;
可以定义一切属性和实体方法;
如果类中有抽象方法,那么类也要生命为抽象类;
有构造方法,但是不可以被实例化;
子类是正常类,父类是抽象类,子类必须重写父类方法,反之不用。
抽象方法:
生来就是被重写的,但是不能被final/private/static修饰,因为最终、私有和静态方法都不能被重写;
可以被重载;
接口:
概念:一个类使用implements来实现一个接口。需要重写接口中的方法。
一个类可以实现多个接口;
没有构造方法;
接口中方法默认使用public abstract ,属性使用public static final修饰
接口和抽象类区别:
接口中一定有抽象方法?看jdk,1.7及其以前是一定的,1.8及其以后就是不一定。
另外
类与类之间是单继承---树形结构--关系判断迅速;
类与接口、接口与接口之间是多实现、多继承--网状结构--两个对象之间关系很难确定,而且编译和运行时期都要确定,所 以规定编译时期不检测对象声明类之间的关系,而在运行时期再去实际的检测,如果不是就报错。
Lambda表达式:--(参数列表)->{重写抽象方法的方法体}
- 用来重写接口中抽象方法。前提是接口中只有一个抽象方法
- 另外,如果抽象方法的方法体只有一句话就可以省略return和{}。
- 如果抽象方法已经有了名且的参数的数据类型就可以省略,如果只有一个参数参与运算而且方法体也只针对这个参数操作就可以写成::传递方法。
- 接口中只有一个抽象方法时-->函数式接口
内部类:(没有说明就是默认可以使用外部类的属性和方法,默认不可以定义静态属性和方法)
方法内部类:
只能在定义的方法内部使用;
只能定义非静态属性和方法和静态常量;
成员内部类:
类内方法外;
只能定义非静态属性和方法和静态常量;
静态内部类:
类内方法外,随着外部类一同加载;
可以定义静态属性和方法
只能访问外部类静态属性和静态方法;
匿名内部类:
匿名内部类就是继承类或者实现接口,去重写抽象方法,只在它创建的时候使用一次;
另外,接口定义接口、接口中定义内部类类、类中定义接口要求内部的东西都是静态的;
垃圾回收机制:
针对对象:堆内存
首先对象创建的时候,先放到新生代(发生在新生代的回收成为初代回收),如果在新生代中的伊甸园区经过扫描一次依然存在,就挪的幸存区,在多次扫描后如果依然存在,则放到老生代,而老生代的扫描频率远远低于新生代,老生代的回收成为完全回收;
API:Application Programming Interfaces应用程序接口,提供接口以及接口以下的所有类。
Object:是所有类的*父类---是java中唯一一个没有父类的类。
clone()---返回一个内容已被拷贝在一块新堆内存中的新对象,如果要实现克隆操作就要先实现Cloneable接口。克隆对象。克隆完成之后会产生一个新的对象,这个新对象和原对象的地址不同但是属性值是一样的。
finalize()---通知系统进行垃圾回收,等同于System.gc()。
getClass()---返回实际创建的类,或者运行类。
hasCode()---返回一个对象的哈希代码值,码值在0-2^31约40亿左右,散列分布,造成数值唯一,来表示地址hascode的值跟程序、对象、运行时期都有关系。
toString()---返回对象的字符串表示形式。以后也会进行频繁重写。
equals()默认是比较地址值,可以重写自己定义:
1.判断地址值
2.参数对象是否为null
3.对象类型是否一致
4.比较属性
手写equals方法
字符串的重写equals方法会去判断字符串的值是否相等。
面试总结:==和equals有什么区别?
当比较基本类型的时候,==判断的是实际数据;对于引用类型而言==判断的是地址。
equals只能作用于引用类型,默认比较的是两个对象的地址;当重写equals的时候按照重写之后的要求进行比较。
有关String的辨析:
String s;//声明一个变量,没有分配内存
String s=null;//没有对象产生
String s="";//创建一个字符串为空的字符串对象
String s = “ ”; //有1个对象,存储在常量池中,值为空即null。
String s = new String(); //堆内存中存储一个对象,值为空。
String s = new String(“abc ”); //2个对象一个堆内存中,一个方法区中--String类型的一个构造方法String(String str)传入的参数也是一个对象,所以就是两个对象。如果字符串常量池中已经有了String a ="abc",那么就是一个对象
只有使用"文本"方式创建的String对象之间使用”+“链接产生的新对象才会被加入字符串池中。对于所有包含new方法创建的对象使用”+“都不会被加入字符串池中。
null
null是关键字,大小写敏感;
null是引用数据类型的默认值;
null既不是对象也不是一种数据类型,它仅仅是一种特殊的值,你可以将其赋予任何引用类型,也可以将null强制转化成任何类型。如
String str=(String)null;
Integer I = (Integer)null;
不能使用非静态方法来使用一个值为null的引用类型变量,将会跑出空指针异常。但是可以使用静态方法使用一个值为null的引用类型变量。因为静态方法使用静态绑定,不会跑出空指针异常
null和空不一样,null表示一个字符串对象的引用指向null,也就是说还没有指向任何的内存空间;
空表示声明一个字符串类型的引用,其值为"",这个str引用指向的是空字符串的内存空间;
Test t = null;
t.普通方法//报错
t.静态方法//没有问题
方法内的变量必须初始化,静态成员变量可以不用初始化,会有系统默认值。
还可以把null传递给方法如:
Public void print(Object obj){…}--->print(null)不会报错,只会优雅的退出。
|
接口 |
抽象类 |
定义 方法
|
全部为抽象方法,默认被public abstract修饰,jdk1.8中允许加上default或者static把抽象方法变成实体方法 |
抽象方法和普通方法; 不必须有抽象方法 |
属性 |
可以定义,默认被public static final修饰,直接定义即可 |
可以定义 |
是不是类 |
不是类 |
是类 |
使用方法 |
interface 类名 |
abstract class 类名 |
能否创建对象 |
不能 |
不能,但是有构造方法 |
与类的关系 |
类可以实现多个接口 |
单继承 |
与自身关系 |
接口可以继承接口,而且 支持多继承 |
抽象类可以继承抽象类 |
包装类:
针对基本数据类型提供了各种操作的类---包装类。
byte |
short |
char |
int |
long |
float |
double |
boolean |
void |
Byte |
Short |
Character |
Integer |
Long |
Float |
Double |
Boolean |
Void |
(自动)封箱--将基本数据类型转成对应的包装类。
int i=1;
Integer in = new Integer(i);//底层调用valueOf方法自动封箱
(自动)拆箱--将包装类转成对应的基本数据类型。
Integer in=new Integer(5);
int i=in;//底层通过对象调用int intValue()自动拆箱
需要注意以下几点:
1.在-128-127范围内,如果两个基本数据类型的值相等,那么这两个包装类对象地址值同样相等;反之,地址值则不相等。
2.由于自动封箱的问题,所以值在-128到127之间的时候会进行判断,如果值在-128到127之间,会直接指向常量池。如果不在这个范围内,会在底层new integer(value)实际上指向了堆内存。如果包装类和对应的数据类型做操作会进行自动拆箱。
3.字符串转成不同类型的包装类,在转换的过程中都会会检测符号;一旦出现非数字符号会报出数据格式异常;
Integer in=new Integer("-123x");//NumberFormatException
Double in=new Double("2.345");
字符串转成基本类型,通过static int parseInt(String s)注意,字符没有该方法。
Boolean(String s)仅当传入字符串入不为null且不区分大小写时等于"true"才会返回true。传入其他字符串都会返回false
4.
字面值的哈希码值都是固定的,所以当传入常量值时,哈希码值就是字面值本身。
包装类对象的哈希码值都是固定的。
Boolean包装类的对象的hashCode返回值如果传入的是true,就返回1231;如果是false,就返回1327.
null的哈希码值默认是0;
Double.NaN==Double.NaN返回false;
另外关于hashcode方法
Public int hashCode()
这个方法返回对象的散列码,返回值是int类型的散列码
关于hashCode方法,一致的约定是:
重写了equals方法的对象也要重写hashCode方法。
第一:在某个运行期间,只要对象的(字段)变化不会影响equals方法的决策结果,那么,在这个期间,无论调用多少次hashCode,都必须返回同一个散列码;
第二:通过equals调用返回true的两个对象的hashCode一定一样
第三:通过equals返回false的两个对象散列码不需要不同,也就是他们的方法的返回值允许出现相同的情况。
总结:等价的对象必须产生相同的散列码。不等价的对象,不要求产生的散列码不相同。空对象的哈希码值为0
A instanceof B
A是一个对象(使用new实例的对象)
B是一个类
Father f = new Son()
f instanceof Son true f引用的实例就是一个Son实例
f instanceof Father true
f instanceof Object true
equals()公约:
自反性: x.equals(x),一定true
对null:x.equals(null),一定false
对称性:x.equals(y),则y.equals(x)
String:
字符串底层是final修饰的char类型的数组,是一个最终类,因此不能被继承。
创建之后不能改变,可以共享--底层有一个不可改变的字符数组。
所有常量都要放到常量池,字符串在常量池是地址的形式存在,其他常量存储的是真实值。
任意字符串都是String类的对象;
堆里存放字符串的值,运行池里存放的是对地址的引用,运行池里的地址指向堆里的字符串存放区,而栈里的变量则指向运行池里的存放地址的地址。
来看两道题目
ab链接之后还会在创建一个new StringBuilder对象
字符串拼接和StringBuilder拼接谁更高效?
1.空间
字符串拼接:
String S="";//存储拼接结果,1个对象
for(String i:S){
s+=i;//创建了3*100=300个对象
}
StringBuilder拼接
StringBuilder sb = new StringBuilder();//1
for(String i:str){
sb.append(i);//1*100=100
}
2.时间
字符串拼接100000个字符串花费3420ms,StringBuilder拼接1000000个字符串花费15ms---所以拼接多个字符串优先选择StringBuilder来拼接。
StringBuilder执行效率高,但是线程不安全--jdk1.5
StringBuffer执行效率低,但是线程安全--jdk1.0
String str="wduv";
System.out.println(str.replaceAll("d", "c"));wcuv
System.out.println(str);wduv
字符串类是声明为final的,替换只不过是生成了一个新的字符串,StringBuilder弥补了String的不足。
有关String的辨析:
String s;//声明一个变量,没有分配内存
String s=null;//没有对象产生
String s="";//创建一个字符串为空的字符串对象
String s = “ ”; //有1个对象,存储在常量池中,值为空即null。
String s = new String(); //堆内存中存储一个对象,值为空。
String s = new String(“abc ”); //2个对象一个堆内存中,一个方法区中--String类型的一个构造方法String(String str)传入的参数也是一个对象,所以就是两个对象。如果字符串常量池中已经有了String a ="abc",那么就是一个对象
只有使用"文本"方式创建的String对象之间使用”+“链接产生的新对象才会被加入字符串池中。对于所有包含new方法创建的对象使用”+“都不会被加入字符串池中。