目录
基本数据类型
- byte、short、int、long、float、double、char、boolean
- 响应封装类 Byte、Short、Integer、Long、Float、Double、Character、Boolean
static
什么时候用static?
不依赖实例和需要共享就可以用static,减少资源消耗。
static关键字最基本的用法是?
- 被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来
- 被static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来
被static修饰的变量、被static修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。
- 静态方法里面不能引用非静态资源,从JVM的类加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类new的时候加载的。 比如Class.forName(“xxx”)方法,就是初始化了一个类,但是并没有new它,只是加载这个类的静态资源罢了。
- static代码块也是static的重要应用之一。也是用于初始化一个类的时候做操作用的,和静态变量、静态方法一样,静态代码块的代码只执行一次,且只在初始化类的时候执行。
instanceof关键字(类型转换)
可以判断两个类之间是否存在父子关系。
// Object -> Person -> Student
// Object -> Person -> Teacher
Object obj = new Student();
System.out.println(obj instanceof Object); // true
System.out.println(obj instanceof Person); // true
System.out.println(obj instanceof Teacher); // false
System.out.println(obj instanceof String); // false
内部类
成员内部类
final 、 finally 、finalize的区别
1、final
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可以被改变
final class A = new A(xx);
final class B = new B(xxx);
A.变量 = 10;
A = B;
最后一句报错,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的。也就是变量本身的值可以改变,但是不可被其他引用类型重新赋值。
2、finally
finally 是用于异常处理的场面,无论是否有异常抛出,都会执行
3、finalize
是Object的方法,所有类都继承了该方法。用于释放资源。
static和final一起用?
static和final的意义是不同的。
static修饰的时候代表对象是静态的,而final修饰的时候代表对象只能赋值一次。
他们一起用的时候是因为定义的那个对象既要它是静态的,也要求它的值不能再被修改
举例说明
static int a=1;
static final b=1;
这里a和b的区别在于,a在程序里可以被重新赋值为2或3或等等的整数,而b在程序里不能被重新赋值,b永远都为1,也就是说b是一个常量。
final int c=1;
static final b=1;
这里c和b的区别在于,b存放在静态空间,是静态资源,它永远在内存中直到程序终止,而c在程序用完它而不会再用到它的时候就会被自动释放,不再占用内存。
当一个常数或字符串我们需要在程序里反复反复使用的时候,我们就可以把它定义为static final,这样内存就不用重复的申请和释放空间。
面向对象
- 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
- 继承:继承是从已有类得到继承信息创建新类的过程。
- 封装:通常认为封装是把数据和方法绑定起来,对数据的访问只能通过已定义的接口。
- 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。实现多态需要做两件事:
— (1). 方法重写(子类继承父类并重写父类中的方法);
— (2). 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)
多态的好处:提高了代码的维护性;提高了代码的拓展性。
Object类方法
Object是所有类的父类,任何类都默认继承Object。
(1)clone方法
实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
(2)getClass方法
final方法,获得运行时类型。
(3)toString方法
该方法用得比较多,一般子类都有覆盖。
(4)finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
(5)equals方法
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
(6)hashCode方法
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
(7)wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
(8)notify方法
该方法唤醒在该对象上等待的某个线程。
(9)notifyAll方法
该方法唤醒在该对象上等待的所有线程。
String
String类是final类,不可以被继承。
- charAt(index) 返回指定位置字符
- trim() 返回一个新字符串,去掉了两边的空白字符
- concat() 连接字符串
- length() 长度
- substring(x,y) 返回字符串的子串
- indexOf / lastIndexOf 返回第一个或最后一个匹配的字符或字符串
- append 拼接字符串
String、StringBuffer、StringBuilder
- String被final修饰,是只读字符串,也就意味着String引用的字符串内容是不能被改变的。
而StringBuffer类表示的字符串对象可以直接进行修改 - StringBuffer 是线程安全的 (同一时间,只有一个线程能够进入这种类的一个实例 的去修改数据)
- StringBuider 非线程安全
引用
boolean b = true;
char c = 'c';
String str = “123”;
1、b、c、str这些等号左边第一个出现的指的是一个引用,引用的内容是等号右边数据在常量池中的地址
2、true、c、123,这些等号右边的指的是编译期间可以被确定的内容,都被维护在常量池中
3、boolean、char、String这些是引用的类型
Equals 和 == (重要)
1、==
- 基本数据类型:比较的是值
- 引用数据类型:比较的是内存地址
2、equals
- 没有覆盖 equals()方法时,则通过 equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。比较的是内存地址
- 重写了equals方法时,例如String,Boolean、Character、Byte、Shot、Integer、Long、Float、Double这些封装类型,equals比较的是地址里的内容,因为他们都重写了equals方法,而==对引用类型比较的是地址。
例子1
String str0 = "123";
String str1 = "123";
System.out.println(str0 == str1); // true
第一行,编译的时候,在常量池中创建了一个常量"123",然后第二行String str1 = “123”,先去常量池中找有没有这个"123",发现有,str1也指向常量池中的"123",所以第七行的str0 == str1返回的是true。因为str0和str1指向的都是常量池中的"123"这个字符串的地址。
例子2
String str2 = new String("234");
String str3 = new String("234");
System.out.println(str2 == str3); // false
Java虚拟机的解释器每遇到一个new关键字,都会在堆内存中开辟一块内存来存放一个String对象,所以str2、str3指向的堆内存中虽然存储的是相等的"234",但是由于是两块不同的堆内存,因此str2 == str3返回的仍然是false。
Integer类的==
例子
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System. out.println( f1 == f2); //true
System. out.println( f3 == f4); //false
以上例子为给一个Integer赋予一个int类型,会自动调用Integer中的静态方法ValueOf()。
Integer f1 = Integer.valueOf(100);
Integer f3 = Integer.valueOf(200);
思考:那么Integer.valueOf()返回的Integer是不是是重新new Integer(num);来创建的呢?如果是这样的话,那么== 比较返回都是false,因为他们引用的堆地址不一样。
具体来看看Integer.valueOf的源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
从上面我们可以知道给Interger 赋予的int数值在[-128,127]的时候,直接从cache中获取,这些cache引用对Integer对象地址是不变的,但是不在这个范围内的数字,则new Integer(i) 这个地址是新的地址,不可能一样的。
练习
public static void main(String[] args) {
Integer a = new Integer(3);
Integer b = 3;
int c = 3;
System.out.println(a == b);
System.out.println(a == c);
}
- a == b:b从cache中获取,a为new的内存地址,故为false;
- a == c:一个Integer 与 int比较,先将Integer转换成int类型,再做值比较,所以返回的是true。
拓展
java中还有与Integer类似的是Long,它也有一个缓存,在区间[-128,127]范围内获取缓存的值,而Long与long比较的时候先转换成long类型再做值的比较
Double类型,它没有缓存,但是当Double与double比较的时候会先转换成double类型,再做值的比较
Java 抽象类
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
抽象方法
抽象方法只包含一个方法名,而没有方法体。该方法的具体实现由它的子类确定。
public abstract class Employee
{
private String name;
private String address;
private int number;
public abstract double computePay(); // 只能有方法体
public void test()
{
System.out.println("TEST");
}
//其余代码
}
继承必须重写父类的抽象方法
/* 文件名 : Salary.java */
public class Salary extends Employee
{
private double salary; // Annual salary
public double computePay()
{
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
//其余代码
}
声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,除非该子类也是抽象类。
abstract class和interface有什么区别?
抽象类和接口类的区别
使用方式
- 抽象类只能通过继承被使用
- 接口必须通过实现被使用
实现方法
- 接口中的方法默认是public,所有方法在接口中不能有实现,而抽象类可以有非抽象的方法,非抽象的方法有它的实现方法。
- 接口只能提供抽象方法。不能提供具体方法。JAVA8版本开始,接口可以提供实现方法了,前提是要在方法前加一个default修饰符
关键字:throws,throw,try,catch,finally
- throws 用在方法声明上面,表示该方法有可能抛出某个异常
- throw 抛出一个指定的异常
- try catch 在try中有可能会抛出某个异常,一旦某个异常抛出后,就会在catch中进行捕捉,他俩一般说来都是成对出现的。
- finally: 表示无论是否捕捉住异常,都会执行
Error和Exception的区别
Exception和Error都是继承了Throwable类
- Error是指正常情况下,不大可能出现的情况
- Exception,可以进行进行捕获处理或者抛出异常
try和finally中都有return
public int test(){
try {
return 3;
}finally {
return 5;
}
}
输出结果为5。
在java中, try 中的 return 语句会先执行,finally 语句后执行,但try中的 return 并不是让函数马上返回结果,而是 return 语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行 finally 语句后才真正开始返回。但此时会出现两种情况:
- 如果finally中也有return,则会直接返回finally中的return结果,并终止程序,函数栈中的return不会被完成
- 如果finally中没有return,则在执行完finally中的代码之后,会将函数栈中保存的try return的内容返回并终止程序
位运算符(左移、右移)
运算规则: 按二进制形式把所有的数字向左移动对应的位数。
3 << 2 :将数字3左移2位 ,首先把3转换为二进制数字0000 0011,数字都朝左平移2位,得到0000 1100,则转换为十进制是12。右移同理,但是要低位移出。
数学意义:右移(>>)一位相当于除2,左移(<<)一位都相当于乘以2的1次
五个你最常见到的runtime exception。
1、NullPointerException 空指针异常
String str = null;
System.out.println(str.length());
2、ArithmeticException 算术异常,比如除数为零
int a = 1/0;
3、IndexOutOfBoundsException 数组下标越界异常
int[] a = new int[1];
System.out.println(a[2]);
4、ClassCastException 类型转换异常
Object obj = new String("123");
System.out.println((Integer)obj);
5、ClassNotFoundException 找不到class
可能没导包?
重载与重写
重载:在同一个类里面,方法名一样,但是参数列表不一样(混淆点:跟返回类型没关系 )
以下方法不构成重载,会报错。(两个方法是一个方法,跟返回类型没关系 d)
public double add(int a,int b)
public int add(int a,int b)
重写:发生在父类子类之间,方法名相同,参数列表相同。子类继承了父类的某个方法后,重新又写了一遍
Session和cookie
Cookie 一般用来保存用户信息 ,Session 的主要作用就是通过服务端记录用户的状态。
session机制是一种服务端的机制,服务器使用一种类似散列表的结构保存信息,当程序需要为某个客户端的请求创建一个session的时候,服务器先检查是否已包含一个sessionID,如果找到,服务器就把这个session检索出来。找不到就创建一个session。
- Cookie的数据存在客户的浏览器(本地)
- Session数据放在服务器上。
session典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。
多线程
-
equals和"=="
-
String字符串
String变量存的是对String对象的引用,String对象里存的才是字符串的值。Sting变量、String对象和字符串值是不同的
-
正则表达式
- c/d 个位数,等同于[0-9]
- [a-e[m-p]] ,a到e或m到p
- 任何的字母,数字或者下划线 [a-Za-z0-9_]
- 量词符:*、+、?、{n}、{n,m} 用于确定量词符前面的模式会重复多少次
- 例如 社会安全号模式是xxx-xx-xxx,正则表达式为:[\d]{3}-[\d]{2}-[\d]{3} “123-12-123”.matches("[…]") 为ture
- 姓名由25个字母组成,第一个为大写,则描述为:[A-Z][a-zA-Z]{1,24}
- StringBulider和StringBuffer
比String更灵活,可以添加、插入新的内容,但是String对象一旦创建它的值就确定了- StringBuffer:如果是多任务并发访问,就使用StringBuffer
- StringBulider:单任务访问更有效
StringBuffer stringBuffer = new StringBuffer();
- append方法:stringBuffer.append(“welcome”); stringBuffer.append(’ ');
- reverse方法:倒置StringBuffer中的字符
- insert(int,char[])
- toString()
- substring()
- Java继承(extends)
- 在Java语言的继承中,在执行子类的构造方法之前,先调用父类的无参构造函数,以帮助继承自父类的成员做初始化操作。如果要调用父类的有参构造函数,要在第一行用super(xxx,xxx)方法。
- 覆盖:在子类中,定义名称、参数个数与类型均与父类中完全相同的方法,用于实现重写父类中同名方法的功能。
- JDK1.8
- JDK、JRE、JVM区别
- JDK:Java编译和运行环境
- JRE:Java运行环境,用于解释执行Java的字节码文件
- JVM:Java虚拟机,是JRE的一部分,负责解释执行字节码文件,是可运行java字节码文件的虚拟计算机。
- JDK包含JRE,JDK和JRE都包含JVM,JVM是Java编程语言的核心