Java笔记(基础梳理)
菜鸟教程里,java基础很全面,透彻了
https://www.runoob.com/java/java-intro.html
1.java数据类型
java是强类型语言,变量在使用前必须声明来指明其数据类型。
- 基本数据类型:byte、short、int、long、float、double、boolean、char
- 引用数据类型:数组、类、接口、枚举、标注、String类
数据类型之间的转换:自动类型转换和强制类型转换
自动:从小到大
强转:从大到小
int a = (int)10.9
2.运算符
算数运算符:+、-、*、/、%
字符串连接运算符:+(平时生产中基本不用,用String的concat方法实现字符串拼接)
关系/比较运算符:>、>=、<、<=、==、!=,关系运算符返回boolean类型
自增减运算符:++、–,只能用于变量,使得当前变量自身的数值加(减)1的效果
逻辑运算符:&&、||、!,返回boolean表达式
三目运算符(常常用作简单的取最大值):条件表达式? 表达式1: 表达式2
int a = 2;
int c = 3;
int b = (a > c) ? a : c;
赋值运算符:=、+=、-=、*=、/=、%=
移位运算符(不常用):<<、>>、>>>
位运算符(不常用):&、|、~、^
3.流程控制语句
分支结构:if分支、Switch分支
if分支结构:
if(a>0){
log.info("开始执行a>0的分支");
}
if-else分支结构:
if(a>0){
log.info("开始执行a>0的分支");
}esle{
log.info("执行else分支")
}
if-else if-else分支结构:
if(a<1000){
log.info("开始执行a<1000的分支");
}else if(a<2000){
// 生产环境中涉及区间值,一般都是左闭右开原则
log.info("开始执行1000<=a<2000的分支");
}esle if(a<3000){
log.info("开始执行2000<=a<3000的分支");
}esle{
log.info("开始执行a>=3000的else分支");
}
switch case分支结构:
// 例子:考试成绩判断
switch(score / 10){
case 0;
case 1;
case 2;
case 3;
case 4;
case 5;
System.out.println("不及格");
break;
case 6;
case 7;
System.out.println("及格");
break;
case 8;
System.out.println("良好");
break;
case 9;
System.out.println("优秀");
break;
case 10;
System.out.println("满分");
break;
}
注意点:只有碰到break才会跳出分支,如果case的字面值后没有break,会执行下个case的语句块,直到碰到break为止。
循环结构:for循环、双重for循环、while循环、do while循环
4.数组
• 可以直接通过下标(或索引)的方式访问指定位置的元素,速度很快。
• 数组要求所有元素的类型相同。
• 数组要求内存空间连续,并且长度一旦确定就不能修改。
• 增加和删除元素时可能移动大量元素,效率低。
// 声明一个数组,遍历数组
int[] intArray = {1,2,3,4,5};
for(int i : intArray){
System.out.println(i);
}
// 二维数组,遍历
int[][] intDoubleArray = {{1,2,3},{4,5,6},{7,8,9}};
for(int i=0;i < intDoubleArray.length;i++){
for(int j=0;j < intDoubleArray[i].length;j++){
System.out.println(intDoubleArray[i][j]);
}
}
数组工具类:java.util.Arrays
// 声明一个数组
int[] intArray = {1,9,9,4,12,88,320,768};
// 正序排序api
Arrays.sort(intArray);
// 输出数组内容
System.out.println(Arrays.toString(intArray));
// 找元素为止
int findSet = Arrays.binarySearch(intArray,320);
System.out.println(findSet);
5.方法和封装
- 成员方法体主要用于编写描述该方法功能的语句块。
- 成员方法可以实现代码的重用,简化代码。
构造方法
构造方法名与类名完全相同并且没有返回值类型,连void都没有。
使用new关键字创建对象时会自动调用构造方法实现成员变量初始化工作。
重载
重载(overload) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
例子:ArrayList的三种构造方法,指定长度、无参数、直接Collection转换ArrayList
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
this关键字
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
- this关键字本质上就是当前类类型的引用变量。
this就相当于“我的”,
当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之不同。
递归(套娃)
递归本质就是指在方法体的内部直接或间接调用当前方法自身的形式
注意点:
- 使用递归必须有递归的规律以及退出条件。
- 使用递归必须使得问题简单化而不是复杂化。
- 若递归影响到程序的执行性能,则使用递推取代之。
// 阶乘n!
int recursive(int n) {
if (0 == n) {
return (1);
}
else {
return n * recursive(n - 1);
}
}
过程:
4*recursive(4-1)
4*recursive(3)
4*3*recursive(3-1)
4*3*recursive(2)
4*3*2*recursive(2-1)
4*3*2*recursive(1)
4*3*2*1*recursive(1-1)
4*3*2*1*recursive(0)
4*3*2*1*1
封装
- 私有化成员变量,使用private关键字修饰。
- 提供公有的get和set方法,并在方法体中进行合理值的判断。
- 在构造方法中调用set方法进行合理值的判断。
属性私有(private)
get、set方法公有(public)
6.static关键字
static表示“全局”或者“静态”的意思,指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间
修饰成员变量:static修饰的成员可以通过类名加“.”进行直接访问
修饰成员方法:static修饰的方法可以通过类名加“.”进行直接访问,常常用于配置信息或者工具类的API,还有main方法
构造块与静态代码块
- 构造块:在类体中直接使用{}括起来的代码块。
- 每创建一个对象都会执行一次构造块。
- 静态代码块:使用static关键字修饰的构造块。
- 静态代码块随着类加载时执行一次
执行顺序:
静态代码块,静态,其作用级别为类,
构造代码块、构造函数,构造,其作用级别为对象。
所以执行顺序肯定是:静态代码块 > 构造代码块 > 构造方法
单例设计模式
**意图:**保证一个类仅有一个实例,并提供一个访问它的全局访问点。
**主要解决:**一个全局使用的类频繁地创建与销毁。
**何时使用:**当您想控制实例数目,节省系统资源的时候。
**如何解决:**判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
**关键代码:**构造函数是私有的。
public class SingleObject {
//创建 SingleObject 的一个对象
private static SingleObject instance = new SingleObject();
//让构造函数为 private,这样该类就不会被实例化
private SingleObject(){}
//获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
public class SingletonPatternDemo {
public static void main(String[] args) {
//不合法的构造函数
//编译时错误:构造函数 SingleObject() 是不可见的
//SingleObject object = new SingleObject();
//获取唯一可用的对象
SingleObject object = SingleObject.getInstance();
//显示消息
object.showMessage();
}
}
成产中用饿汉式,就上面那种,基于类加载机制避免了多线程的同步问题
7.继承
在Java语言中使用extends(扩展)关键字来表示继承关系
public class Worker extends Person{} - 表示Worker类继承自Person类
使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件
特点:
-
子类拥有父类非 private 的属性、方法。
-
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法。
-
Java 不支持多继承,但支持多重继承,A extends B,B extends C
重写(override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
继承下的构造块与静态代码块
- 先执行父类的静态代码块,再执行子类的静态代码块。(static修饰的都是在类加载的时候就执行的)
- 执行父类的构造块,执行父类的构造方法体。
- 执行子类的构造块,执行子类的构造方法体。
访问控制
public(都可以访问)
protected(其他类不能访问、子类可以)
默认(子类不能访问)
private(只有本类可以访问)
成员方法都使用public关键字修饰,成员变量都使用private关键字修饰
final关键字
final 修饰类:最终类,不能被继承,其中的方法自动变成final修饰,但变量不是final修饰
final 修饰方法:最终方法,不能被子类重写
final 修饰变量:该变量不能被修改
8.多态
多态主要指同一种事物表现出来的多种形态。
多态的优点:
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态的三个必要条件:
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
例子:
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
9.抽象类和抽象方法
相关概念:
-
抽象方法不可实现,没有方法体
-
拥有抽象方法的类必须是抽象类
-
因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类
意义
- 抽象类的实际意义不在于创建对象而在于被继承
- 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类
- 抽象类对子类具有强制性和规范性,称之为模板设计模式
10.接口
相关概念:
接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法。
定义类的关键字是class,而定义接口的关键字是interface。
类和接口之间的关系:
类和类之间的关系——extends——支持单继承
类和接口之间的关系——implements——支持多实现
接口和接口之间的关系——extends——支持多继承
11.特殊类
内部类:一个类中可以嵌套另外一个类
class OuterClass { // 外部类
// ...
class NestedClass { // 嵌套类,或称为内部类
// ...
}
}
匿名内部类
匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为 Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
例子:
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
// 格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
Person p = new Person() {
public void eat() {
System.out.println( "eat something" );
}
};
p.eat();
}
}
枚举
- 使用public static final表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量
- java5开始有枚举
- 枚举类常用api
注解
- 注解Annotation,引用数据类型
- 注解本质上就是代码中的特殊标记,通过这些标记可以在编译、类加载、以及运行时执行指定的处理
- 自定义注解自动继承java.lang.annotation.Annotation接口。
- 通过@注解名称的方式可以修饰包、类、 成员方法、成员变量、构造方法、参数、局部变量的声明等。
- Annotation 是一个辅助类,它在 Junit、Struts、Spring 等工具框架中被广泛使用。
作用:
- 编译检查:@SuppressWarnings, @Deprecated 和 @Override 都具有编译检查作用
- 在反射中使用 Annotation:
import java.lang.annotation.Annotation;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Inherited;
import java.lang.reflect.Method;
/**
* Annotation在反射函数中的使用示例
*/
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String[] value() default "unknown";
}
/**
* Person类。它会使用MyAnnotation注解。
*/
class Person {
/**
* empty()方法同时被 "@Deprecated" 和 "@MyAnnotation(value={"a","b"})"所标注
* (01) @Deprecated,意味着empty()方法,不再被建议使用
* (02) @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown"
*/
@MyAnnotation
@Deprecated
public void empty(){
System.out.println("\nempty");
}
/**
* sombody() 被 @MyAnnotation(value={"girl","boy"}) 所标注,
* @MyAnnotation(value={"girl","boy"}), 意味着MyAnnotation的value值是{"girl","boy"}
*/
@MyAnnotation(value={"girl","boy"})
public void somebody(String name, int age){
System.out.println("\nsomebody: "+name+", "+age);
}
}
public class AnnotationTest {
public static void main(String[] args) throws Exception {
// 新建Person
Person person = new Person();
// 获取Person的Class实例
Class<Person> c = Person.class;
// 获取 somebody() 方法的Method实例
Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class});
// 执行该方法
mSomebody.invoke(person, new Object[]{"lily", 18});
iteratorAnnotations(mSomebody);
// 获取 somebody() 方法的Method实例
Method mEmpty = c.getMethod("empty", new Class[]{});
// 执行该方法
mEmpty.invoke(person, new Object[]{});
iteratorAnnotations(mEmpty);
}
public static void iteratorAnnotations(Method method) {
// 判断 somebody() 方法是否包含MyAnnotation注解
if(method.isAnnotationPresent(MyAnnotation.class)){
// 获取该方法的MyAnnotation注解实例
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
// 获取 myAnnotation的值,并打印出来
String[] values = myAnnotation.value();
for (String str:values)
System.out.printf(str+", ");
System.out.println();
}
// 获取方法上的所有注解,并打印出来
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation);
}
}
}
- 根据 Annotation 生成帮助文档:通过给 Annotation 注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中
){
// 获取该方法的MyAnnotation注解实例
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
// 获取 myAnnotation的值,并打印出来
String[] values = myAnnotation.value();
for (String str:values)
System.out.printf(str+", ");
System.out.println();
}
// 获取方法上的所有注解,并打印出来
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation);
}
}
}
- 根据 Annotation 生成帮助文档:通过给 Annotation 注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中