Java基础内容总结回顾
基础语法
注释
行内注释 //
多行注释 /* /
文档注释 /* */ (javadoc 生成帮助文档)
javadoc:
javadoc -encoding UTF-8 -charset UTF-8 xxx.java
关键字
数据类型
基本数据类型
引用数据类型
类
接口
数组
类型转换
自动类型转换:低转高
强制类型转换:高转低
变量和常量
变量是内存中的一个存储区域,该区域有自己的名称(变量名)和类型(数据类型),Java中每个变量必须先声明,后使用, 该区域的数据可以在同一类型范围内不断变化。
常量是一种特殊的变量,它的值被设定后,在程序运行过程中不允许改变,一般用大写字符
命名规范
1、言简意赅
2、驼峰命名法(变量、方法)
3、类名,首字母大写+驼峰命名
4、常量:大写+下划线
运算符
算术运算符:+ - * / % ++ –
赋值运算符: =
关系运算符: > < >= <= !=
逻辑运算符: || && !
位运算符: & | ^ >> << >>>
条件运算符:?:
扩展运算符:+= -= *= / =
包机制
域名倒写、package、import
流程控制
顺序结构
程序默认结构,自上而下的执行
选择结构
if单选择
if-else 双选择结构
嵌套if选择结构
switch选择结构
switch(表达式){
case 变量1:
语句1;
break;
case 变量2:
语句2;
break;
....
default:
语句3;
}
case穿透现象:switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break语句处或者是switch语句的末尾。如果没有break语句,那么就会从表达式的值相匹配的case标签处开始执行,一直执行到switch语句的末尾,这种从其中的一个case处开始,忽略后面的值的匹配,直接运行case的内容的现象就是穿透的现象。
循环结构
while循环
while(条件表达式){
循环体;
[循环变量的控制部分];
}
do-while循环
do{
循环体;
[循环变量控制语句];
}while(条件表达式);
特点循环体至少会被执行一次
for循环
for(初始化语句;条件判断;循环变量的控制语句){
循环体;
}
while循环和for循环是可以互换的;通常情况下,如果知道循环的次数的话,使用for;不知道循环次数时,使用while,此时也可以使用for
增强for循环
for(元素数据类型 变量:数组或者Collection集合){
使用变量即可
}
缺点
a) 增强for的目标不能是null
b) 解决:对增强for的目标先进行不为null的判断
break & continue
break:跳出循环体
continue:跳出当次循环
return:结束方法的运行
方法
方法就是一段可以被重复调用的方法块
修饰符 返回值 方法名(参数名){
方法体代码;
return 返回值;
}
方法调用
1、类名.方法
2、对象.方法
方法的几种类型
1.无参数无返回值的方法
public void f1() {
System.out.println("无参数无返回值的方法");
}
2.有参数无返回值的方法
public void f2(int a, String b, int c) {
System.out.println(a + "-->" + b + "-->" + c);
}
```java
3.有返回值无参数的方法
```java
public int f3() {
System.out.println("有返回值无参数的方法");
return 2;
}
4.有返回值有参数的方法
public int f4(int a, int b) {
return a * b;
}
在一个静态方法内调用一个非静态成员为什么是非法的?
静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,然后通过类的实例对象去访问。在类的非静态成员不存在的时候静态成员就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
重载与重写
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法
数组
数组定义
方法一:1.先声明 2.分配空间 3.赋值
int[] arr; //先声明
arr=new int[5]; //分配空间
for(int i=0;i<5;i++)arr[i]=i*10; //赋值
方法二:1.声明并分配空间 2.赋值
int[] arr=new int[5]; //声明并分配空间
for(int i=0;i<5;i++)arr[i]=i*10; //赋值
方法三:1.声明并分配空间然后.赋值
int[] arr={20,68,34,22,34}; //声明并分配空间然后.赋值
等同于 int[] arr= new []{20,68,34,22,34};
二维数组
两种初始化形式
格式1: 动态初始化
数据类型 数组名 [ ][ ] = new 数据类型[m][n]
数据类型 [ ][ ] 数组名 = new 数据类型[m][n]
数据类型 [ ] 数组名 [ ] = new 数据类型[m][n]
举例:int [ ][ ] arr=new int [4][4];
格式2: 静态初始化
数据类型 [ ][ ] 数组名 = {{元素1,元素2…},{元素1,元素2…},{元素1,元素2…}…};
举例:int [ ][ ] arr={{1,2,3,4,5},{5,2,3,1,4},{4,5,3,2,1},};
静态初始化可用于不规则二维数组的初始化
排序算法
1、冒泡排序
2、选择排序
3、插入排序
4、快速排序
5、归并排序
6、希尔排序
7、堆排序
8、基数排序
面向对象
面向对象和面向过程的区别
面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性能比面向过程低
类与对象
类是对象的抽象
对象是类的具体
构造方法
特点:
名字与类名相同。
没有返回值,但不能用 void 声明构造函数。
生成类的对象时自动执行,无需调用。
构造方法不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。
封装
封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法(get set方法)来操作属性。
继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。
注:
子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
多态
表示一个对象具有多种的状态。具体表现为父类的引用指向子类的实例。
多态的特点:
对象类型和引用类型之间具有继承(类)/实现(接口)的关系;
引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
多态不能调用“只在子类存在但在父类不存在”的方法;
如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。
接口
接口,是一个抽象类型,是抽象方法的集合,通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
接口与类的区别:
1、接口不能用于实例化对象。
2、接口没有构造方法。
3、接口中所有的方法必须是抽象方法。
4、接口不能包含成员变量,除了 static 和 final 变量。
5、接口不是被类继承了,而是要被类实现。
6、接口支持多继承。
接口特性
接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
异常
try-catch-finally
try块: 用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
catch块: 用于处理 try 捕获到的异常。
finally 块: 无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。
在以下 3 种特殊情况下,finally 块不会被执行:
在 try 或 finally块中用了 System.exit(int)退出程序。但是,如果 System.exit(int) 在异常语句之后,finally 还是会被执行
程序所在的线程死亡。
关闭 CPU。
常用类
object类
public final native Class<?> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。
public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。
protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。
public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。
public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。
public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
protected void finalize() throws Throwable { }//实例被垃圾回收器回收的时候触发的操作
String、StringBuffer和StringBuilder区别
可变性
String 类中使用 final 关键字修饰字符数组来保存字符串,private final char value[],所以String 对象是不可变的。而 StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串char[]value 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
线程安全性
String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
性能
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结:
操作少量的数据: 适用 String
单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer
包装类
自动装箱与拆箱
装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
Integer i = 10; //装箱
int n = i; //拆箱
I/O
获取用键盘输入常用的两种方法
方法 1:通过 Scanner
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
方法 2:通过 BufferedReader
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();
Java 中 IO 流分为几种?
按照流的流向分,可以分为输入流和输出流;
按照操作单元划分,可以划分为字节流和字符流;
按照流的角色划分为节点流和处理流。
Java Io 流共涉及 40 多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。