JAVA基础
一、概述
1、Java简述
Java是一种面向对象编程的语言,有封装,继承,多态,没有多继承;有自带的垃圾回收机制。
2、Java的优缺点
2.1、优点
- JAVA是纯面向对象的语言
- 平台无关性,可移植性强:一次编译,到处执行。.java程序经过编译器,编译成.class的字节码文件,只要不同的系统上面安装了JVM(java 虚拟机)就可以执行这个字节码文件
- JAVA提供了很多内置的类库:简化开发人员的设计工作,同时缩短了项目开发的时间。提供多线程,网络编程,以及垃圾回收的部分
- JAVA提供对WEB应用开发的支持。如Applet,Servlet和JSP可以用来开发WEB应用程序
- 较好的安全性和健壮性:数组边界检测和Bytecode检验。java的强类型机制,垃圾回收机制,异常处理,安全检查机制
2.2、缺点
- 解释型语言,运行效率极低,不支持底层的操作
- 取消了指针,不够灵活(这样安全)
3、JDK有哪些版本
- OpenJDK:开源的,是一个参考模型
- OracleJDK:是OpenJDK的一个实现,比OpenJDK更稳定,在响应和JVM性能上都是非常不错的
4、JDK,JRE,JVM是什么,能做什么?
4.1JVM、
Java Virtual Machine 虚拟机,JAVA程序运行在上面,不同的平台有自己的虚拟机,因此JAVA语言支持跨平台。
4.2JRE、
Java Runtime Environment Java运行时环境:只要机器上安装了JRE就可以运行Java程序(字节码文件)。它是由JVM和核心类库组成
4.3JDK、
Java Development Kit Java开发工具包,包括JRE和开发工具包(编译工具javac.exe,打包工具jar.exe)等
5、Java程序执行的流程
java程序---->经过编译器---->生成.class文件(字节码)---->JVM---->将字节码解释成机器码---->在机器上执行
二、基础语法
1、数据类型
-
基本类型
- 数值型(8):
- 整数类型:byte(1),short(2),int(4),long(8)
- 浮点型:float(4),double(8)
- 字符型:char(2)
- 布尔型:boolean(1)
- 数值型(8):
-
引用类型(3)
- 类
- 接口
- 数组
- String
- Enum
String类型不是基本的数据类型
1.1、短整数short,整数int,长整数long,字节型byte
//短整数类型(-32768----+32767)
short a=32767;
short b=-32768;
System.out.println("a:"+a+'\n'+"b:"+b);
/**
* a:32767
* b:-32768
*/
//整数类型(-2^31----+2^31-1)
int c= (int) Math.pow(2,32768);
int d= (int) Math.pow(2,32767)-1;
System.out.println("c:"+c+'\n'+"d:"+d);
/**
*c:2147483647
*d:2147483646
*/
//长整数类型(-2^64----+2^64-1)
//字节型:当赋值的值不是一个整数时,将这个通过Unicode转化为一个整数
byte age='4';
byte age2='.';
System.out.println("age:"+age);
System.out.println("age2:"+age2);
//字节数组。数组中不是整数的也转化为相应的整数(通过ASCII码,这个是和字符型相反的)
byte[] b = new byte[11];
System.out.println(b);
b[0]=-128;
b[1]=20;
b[2]='a';
b[10]='w';
System.out.println("-------------");
for (i = 0; i< b.length; i++) {
System.out.println(b[i]);
}
1.2、浮点型
- 浮点型(float)
Java的浮点数遵循IEEE754标准,采用二进制数据的科学计数法来表示浮点数,对于float型数值,第1位是符号位,接下里8位表示指数,再接下来的23位表示尾数;
- 双精度型(double)
对于double类型数值,第一位也是符号位,接下来的11位表示指数,再接下来的52位表示尾数。
1.3、字符型
char,一个字符由两个字节存储,但只能表示一个字符,不管是数字还是字符还是其他的符号,都会转化为一个字符。
- 如果是’ '之间的,结果就是单引号之间的、
- 如果是数字,将通过ASCII码转化为一个字符
char a2='2'; //2
char b=97; //a
char c=2; //正文开始
char e=34; //"
char d='#'; //#
1.4、布尔型
true,false
2、运算符
2.1、按位与&和逻辑与&&(短路与)的区别(按位或和逻辑或也一样)
相同点:左右两边都是true,结果才为true
不同点:逻辑与当左边的为false时,不会计算右边的表达式
2.2、运算符的优先级
按位高于逻辑的
优先级 | 运算符 |
---|---|
1 | . () [] |
2 | +(正) -(负) ++ – ~ ! |
3 | * / % |
4 | +(加) -(减) |
5 | << >>(无符号右移) >>>(有符号右移) |
6 | < <= > >= instanceof |
7 | == != |
8 | & |
9 | | |
10 | ^ |
11 | && |
12 | || |
13 | ?: |
14 | 赋值 |
三、面向对象
3、JAVA面向对象的三大特性
封装,继承,多态
3.1、实现多态的三个必要条件和两种实现方式:
- 必要条件:
- 继承,重写,向上转型
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
- 继承:多个子类重写父类的同一个方法
- 接口:实现接口并覆盖接口中的方法
3.2、什么是多态机制?Java语言是如何实现多态的?
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。
3.3、抽象类和接口的对比
抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。
从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
相同点
- 接口和抽象类都不能实例化
- 都位于继承的顶端,用于被其他实现或继承
- 都包含抽象方法,其子类都必须覆写这些抽象方法
不同点
参数 | 抽象类 | 接口 |
---|---|---|
声明 | 抽象类使用abstract关键字声明 | 接口使用interface关键字声明 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现 | 子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
访问修饰符 | 抽象类中的方法可以是任意访问修饰符 | 接口方法默认修饰符是public。并且不允许定义为 private 或者 protected |
多继承 | 一个类最多只能继承一个抽象类 | 一个类可以实现多个接口 |
字段声明 | 抽象类的字段声明可以是任意的 | 接口的字段默认都是 static 和 final 的 |
抽象类的abstract关键字可以修饰类或者方法。
声明一个抽象方法:它是没有方法体的,如果一个类中有抽象方法,那么这个类也必须是抽象类,并且它的继承类要么实现它的抽象方法要么继承类也是抽象类。
为什么要用抽象类 什么情况下用抽象类
- 根本原因:无法完整的描述一个类
- 抽象类中的抽象方法,必须要子类去实现(或者子类也是抽象类就不用去实现,看业务需求)
- 和接口相比:接口里面的方法都要实现,当接口里面的方法比较多的时候,就会很麻烦。但是抽象类就没有限制。
- 易于理解
4、内部类
内部类也就是将类的定义在一个类中定义。分为静态内部类,局部内部类,成员内部类,匿名内部类
4.1、静态内部类(静态的只能使用静态的数据)
有static修饰的内部类,他可以访问类中的外部类的所有静态变量,而不可访问外部类的非静态变量,静态内部类的创建方式,new.外部类().内部类()
4.2、成员内部类
在成员位置定义的内部类,可以访问外部类的所有数据。但是它的实例化需要依赖外部类的实例,外部类实例.new 内部类()
4.3、局部内部类
定义在外部类的方法中,在普通方法中的话,内部类可以访问外部类的所有数据;在静态方法中的话,只能访问外部类的静态资源。局部内部类的实例化只能创建在方法中。new 内部类()
4.4、匿名内部类
没有名字的内部类,开发者比较常用。使用new 内部类()
特点:
- 匿名内部类必须继承一个抽象类或者实现一个接口
- 匿名内部类中不能定义任何静态资源
- 当所在的方法的形参需要被内部类使用时,必须声明为final
内部类的优点
我们为什么要使用内部类呢?因为它有以下优点:
- 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
- 内部类不为同一包的其他类所见,具有很好的封装性;
- 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
- 匿名内部类可以很方便的定义回调。
内部类有哪些应用场景
- 一些多算法场合
- 解决一些非面向对象的语句块。
- 适当使用内部类,使得代码更加灵活和富有扩展性。
- 当某个类除了它的外部类,不再被其他的类使用时。
局部内部类和匿名内部类在访问局部变量时为什么变量加上final?
是因为生命周期不一样,局部变量直接存储在栈中,方法调用结束就会将这个变量销毁,但是内部类对局部变量的引用还存在,如果内部类要调用这个局部变量就会出错,所以要将这个局部变量加上final,这样就不会出错了。
5、重写和重载
方法的重载和重写都是实现多态的方式,区别在于牵着实现的是编译时的多态性,后者是运行时的多态性。
- 重载:只是方法名一样,其他的不同
- 重写:方法名和参数列表必须相同
6、相等和equals的区别
==:作用是判断两个对象的地址是不是相等,即判断两个对象是不是同一个对象(基本数据类型比较的是值,引用数据类型比较的是内存地址)
equals():判断两个对象是否相等,判断是两个对象的地址是否相等。一般会重写类中的equals方法,判断两个对象的值是否相等。equals是Object中的方法,它里面比较的是对象的内存地址,而String中比较的是对象的值。
- new String()创建的对象在堆中存储
- 直接赋值创建的字符串保存在串池中
String a=new String("ab"); //在堆中被创建
String b="ab"; //在串池中被创建
String c="ab"; //引用串池中已近存在的"ab"
System.out.println(a==b); //false,他们的地址不相等
System.out.println(a==c); //false,他们的地址不相等
System.out.println(b==c); //true,b在串池被创建,c引用的b,所以他们的地址相等
System.out.println(a.equals(b)); //true
System.out.println("****");
int age1=10;
int age2=10;
System.out.println(age1==age2); //true
7、散列值和equals方法
hashcode是一个散列值,一个int整数,这个哈希值的作用是该对象在哈希表的索引位置。
哈希表中存储的是key-value,哈希值就是key,value就是对象。它的作用就是快速的检索出对应的值。
那为什么会hashcode呢?
当把对象放在Hashset中,会先计算对象的hashcode来判断对象加入的位置,也会和已经加入的对象的hashcode作比较,如果没有一样的,那么就再将这个对象放到哈希表中;如果有对象的hashcode一样,那么在调用equals方法比较这两个对象是否真的相等,如果相等,不会让其加入hashset,否则。
- hashcode方法默认在堆中产生独特值,一般的话都会重写这个方法。
- 对象的相等比较的是内存中的值是否相等,饮用比较的是指向他们的内存地址是否先等
原始的hashcode 的生成方式是s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
.
8、java的只有值传递
方法调用的参数值(基本类型)只是一个拷贝,不能修改原始值。但是如果参数值是引用类型的话就会修改原始值:::(引用是地址的指向一样,基本类型只是一个拷贝)
四、IO流
1、BIO同步阻塞IO
数据的读取写入必须在一个线程内等待其完成。使用简单方便,并发能力低
2、NIO同步非阻塞IO
客户端和服务端通过channel通讯,实现了多路复用。
3、AIO异步非阻塞IO
基于时间和回调机制
五、反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
静态编译和动态编译
- **静态编译:**在编译时确定类型,绑定对象
- **动态编译:**运行时确定类型,绑定对象
5.1、反射机制优缺点
- 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
- 缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多
5.2、Java获取反射的三种方法
1.通过new对象实现反射机制 2.通过路径实现反射机制 3.通过类名实现反射机制
public class Student {
private int id;
String name;
protected boolean sex;
public float score;
}
public class Get {
//获取反射机制三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
//方式二(所在通过路径-相对路径)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());
}
}
六、常用API
存储字符串可以使用char数组,但String的底层封装了char数组,所以一般使用String来操作字符串。
1、String有哪些特性、
-
不变性:常量字符串不能被修改
-
常量池优化:String创建的对象,保存在串池中,下次创建相同的对象会直接放回其引用。
-
使用final定义String类,表示被继承,提高了系统的安全性
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
//修改String常量 String desc="Spring cloud"; Field valueFieldsOfStrimng = String.class.getDeclaredField("value"); valueFieldsOfStrimng.setAccessible(true); char[]value = (char[])valueFieldsOfStrimng.get(desc); value[5]='@'; System.out.println(desc); //output :Sprin@ cloud
2、String常用的方法
System.out.println(desc.length());
System.out.println(desc.indexOf('o'));
System.out.println(desc.charAt(2));
System.out.println(desc.replace('d','a'));
System.out.println(desc.trim());
String[] array=desc.split(" ");
for (String arr:array) {
System.out.println(arr);
}
System.out.println(array);
System.out.println(desc.toLowerCase());
System.out.println(desc.toUpperCase());
System.out.println(desc.substring(2));
System.out.println(desc.equals(desc.substring(5)));
3、String中的equals方法的实现
有四层的判断
- 首先判断是不是本对象,是的话返回true,不是的话继续做判断
- 判断这个对象的是不是String类的实例,是的话继续判断,不是的话直接返回false
- 继续判断,他们的长度是否相等,是的话继续判断,不是的话直接返回false
- 继续判断,两个对象对应位置的字符是否一样,全部一样返回true,有一个不一样直接返回false
instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
3、String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的
StringBuffer是线程安全的,并有一定的缓存,字符串太大会增加字符创的容量,多线程操作字符创
StringBulider是想成不安全的,单线程操作字符创