一.初始java
1.1 java的语言特性
1.简单性 2.面向对象 3.分布式 4.健壮性 5.安全性 6.体系结构中立
7.可移植性 8.解释性 9.高性能 10.多线程 11.动态性
二.数据类型和变量
2.1 字面常量
1.定义:字面常量即程序运行期间,固定不变的量称为常量
2.字面常量的分类:
1. 字符串常量:由""括起来的,比如“12345”、“hello”、“你好”。
2. 整形常量:程序中直接写的数字(注意没有小数点),比如:100、1000
3. 浮点数常量:程序中直接写的小数,比如:3.14、0.49
4. 字符常量:由 单引号 括起来的当个字符,比如:‘A’、‘1’
5. 布尔常量:只有两种true和false
6. 空常量:null
注意:字符串、整形、浮点型、字符型以及布尔型,在Java中都称为数据类型。
2.2 数据类型
在Java中数据类型主要分为两类:基本数据类型和引用数据类型。
基本数据类型有四类八种:
1. 四类:整型、浮点型、字符型以及布尔型
2. 八种:字节型(byte) 短整型(short) 整型(int) 长整型(long)
单精度浮点数(float) 双精度浮点数(double) 字符型(char) 布尔型(boolean)
注意:
不论是在16位系统还是32位系统,int都占用4个字节,long都占8个字节
整形和浮点型都是带有符号的 整型默认为int型,浮点型默认为double
字符串属于引用类型
2.3 变量
1.定义:经常改变的内容,在Java程序中,称为变量。而数据类型就是用来定义不同种类变量的。
2.类型转换:在Java中,当参与运算数据类型不一致时,就会进行类型转换。Java中类型转换主要分为两类:自动类型转换(隐 式)和强制类型转换(显式)。
自动类型转换即:代码不需要经过任何处理,在代码编译时,编译器会自动进行处理。特点:数据范围小的转为数据范围大的时会自动进行。
强制类型转换:当进行操作时,代码需要经过一定的格式处理,不能自动完成。特点:数据范围大的到数据范围小的。
注意事项:
不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型
如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失
将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查
强制类型转换不一定能成功,不相干的类型不能互相转换
3.类型提升:不同类型的数据之间相互运算时,数据类型小的会被提升到数据类型大的。
三. 运算符
3.1位运算符
1. 按位与 &: 如果两个二进制位都是 1, 则结果为 1, 否则结果为 0.
2.按位或 |: 如果两个二进制位都是 0, 则结果为 0, 否则结果为 1.
3.按位取反 ~: 如果该位为 0 则转为 1, 如果该位为 1 则转为 0
4.按位异或 ^: 如果两个数字的二进制位相同, 则结果为 0, 相异则结果为 1.
四.方法
4.1实参和形参的关系
形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。
在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体
4.2方法重载
在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。
public class TestMethod {
public static void main(String[] args) {
add(1, 2); // 调用add(int, int)
add(1.5, 2.5); // 调用add(double, double)
add(1.5, 2.5, 3.5); // 调用add(double, double, double)
}
public static int add(int x, int y) {
return x + y
}
public static double add(double x, double y) {
return x + y;
}
public static double add(double x, double y, double z) {
return x + y + z;
}
}
注意:
1. 方法名必须相同
2. 参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
3. 与返回值类型是否相同无关
五.类与对象
5.1封装
1.概念:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
2.访问限定符
5.2static成员
1.static修饰成员变量:称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
特性:
不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中.
既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问.
类变量存储在方法区当中.
生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁).
2.static修饰成员方法:被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。
特性:
不属于某个具体的对象,是类方法.
可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者.
不能在静态方法中访问任何非静态成员变量.
六.继承与多态
6.1继承
1.定义:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性 的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
2.父类成员访问
在子类方法中 或者 通过子类对象访问成员时:
如果访问的成员变量子类中有,优先访问自己的成员变量。
如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
3.子类中访问父类的成员方法
同理
3.super关键字
public class Derived extends Base{
int a; // 与父类中成员变量同名且类型相同
char b; // 与父类中成员变量同名但类型不同
// 与父类中methodA()构成重载
public void methodA(int a) {
System.out.println("Derived中的method()方法");
}
// 与基类中methodB()构成重写(即原型一致,重写后序详细介绍)
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
// 对于同名的成员变量,直接访问时,访问的都是子类的
a = 100; // 等价于: this.a = 100;
b = 101; // 等价于: this.b = 101;
// 注意:this是当前对象的引用
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从基类继承下来的部分
super.a = 200;
super.b = 201;
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
methodB(); // 直接访问,则永远访问到的都是子类中的methodA(),基类的无法访问到
super.methodB(); // 访问基类的methodB()
}
}
4.子类构造方法
public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base{
public Derived(){
// super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
// 并且只能出现一次
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}
注::子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子 肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整 ,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。
5.super和this
相同点:
都是Java中的关键字
只能在类的非静态方法中使用,用来访问非静态成员方法和字段
在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
不同点:
this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成 员的引用
6.2多态
1.多态的概念:具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
2.多态的条件:必须在继承体系下 ,子类必须要对父类中方法进行重写 , 通过父类的引用调用重写的方法
3.重写:也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定 于自己的行为。 也就是说子类能够根据需要实现父类的方法。
【方法重写的规则】
子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致
被重写的方法返回值类型可以不同,但是必须是具有父子关系的
访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方 法就不能声明为 protected
父类被static、private修饰的方法、构造方法都不能被重写。
重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心 将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法 构成重写.
即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
6.3向上转移和向下转型
1.向上转移
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用
向上转型的优点:让代码实现更简单灵活。 向上转型的缺陷:不能调用到子类特有的方法。
2.向下转型
将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的 方法,此时:将父类引用再还原为子类对象即可,即向下转换。
向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入 了 instanceof ,如果该表达式为true,则可以安全转换。
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat("元宝",2);
Dog dog = new Dog("小七", 1);
// 向上转型
Animal animal = cat;
animal.eat();
animal = dog;
animal.eat();
if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew();
}
if(animal instanceof Dog){
dog = (Dog)animal;
dog.bark();
}
}
}
6.4多态的优缺点
优点:
1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else
2.可扩展能力更强
缺点:
多态缺陷:代码的运行效率降低。
注:避免在构造方法中调用重写的方法
七.抽象类和接口
7.1抽象类
1.概念:如果 一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类
2.抽象类特性:
抽象类不能直接实例化对象 .
抽象方法不能是 private 的.
抽象方法不能被final和static修饰,因为抽象方法要被子类重写.
抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰.
抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量
7.2接口
1.概念:接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。 在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
2.特性:
接口类型是一种引用类型,但是不能直接new接口的对象
接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)
接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
重写接口中方法时,不能使用默认的访问权限
接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
接口中不能有静态代码块和构造方法
接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
jdk8中:接口中还可以包含default方法。
3.接口间的继承
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
}
class Frog implements IAmphibious {
...
}
问题:java数据结构中为什么常用List来接收ArraryList?
在Java数据结构中,`List`接口和`ArrayList`类是经常一起使用的,这主要有以下几个原因:
1. **多态性**:在Java中,`ArrayList`是`List`接口的一个实现。使用`List`接口作为引用类型可以让我们编写更加灵活和可维护的代码,因为我们可以在不改变代码结构的情况下更换`List`的具体实现(例如,从`ArrayList`切换到`LinkedList`)。
2. **接口隔离原则**:使用接口(如`List`)作为引用类型而不是具体的类(如`ArrayList`),可以帮助我们遵循接口隔离原则,这是一种面向对象的设计原则,它提倡使用多个特定的接口,而不使用单一的总接口,客户端不应该依赖于它们不使用的接口。
3. **代码可读性**:`List`是一个通用的集合类型,表示一个有序的元素集合。在代码中,使用`List`作为引用类型可以让其他开发者更容易理解你的代码意图,而不需要知道具体的实现细节。
4. **类型安全**:使用泛型(如`List<String>`)可以确保我们在集合中存储和检索的数据类型是正确的,从而避免类型转换错误和`ClassCastException`。
5. **性能**:`ArrayList`在内部使用动态数组来存储元素,这使得它在随机访问(即,通过索引访问)元素时具有非常高的效率。这使得`ArrayList`成为许多场景下的理想选择,尤其是当我们需要频繁地访问集合中的元素时。
当然,这并不是说在所有情况下都应该使用`List`来接收`ArrayList`。在某些情况下,使用具体的类(如`ArrayList`)可能更加合适,例如在性能要求非常高,且我们知道集合的大小不会改变的场景下。但总的来说,使用`List`接口作为引用类型是一种更加灵活和可维护的做法。
4.抽象类和接口的区别
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中 不能包含普通方法, 子类必须重写所有的抽象方法
八.异常
8.1 异常的概念与体系结构
1. 异常的概念
在Java中,将程序执行过程中发生的不正常行为称为异常。java中不同类型的异常,都有与其对应的类来进行描述
2.异常的体系结构
Throwable:是异常体系的顶层类,其派生出两个重要的子类, Error 和 Exception
Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表: StackOverflowError和OutOfMemoryError,一旦发生回力乏术。
Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说 的异常就是Exception。
3.异常的分类
编译时异常
在程序编译期间发生的异常,称为编译时异常,也称为受检查异常(Checked Exception)
运行时异常
RunTimeException以及其子类对应的异常,都称为运行时异常
8.2异常的处理
1.事前防御型
缺陷:正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱。
2.事后认错型
优势:正常流程和错误流程是分离开的, 程序员更关注正常流程,代码更清晰,容易理解代码 异常处理的核心思想就是 EAFP。异常处理主要的5个关键字:throw、try、catch、final、throws。
异常处理流程总结
程序先执行 try 中的代码
如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
如果找到匹配的异常类型, 就会执行 catch 中的代码
如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
如果上层调用者也没有处理的了异常, 就继续向上传递.
一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.
8.3自定义异常类
1. 自定义异常类,然后继承自Exception 或者 RunTimeException
2. 实现一个带有String类型参数的构造方法,参数含义:出现异常的原因
注意事项
自定义异常通常会继承自 Exception 或者 RuntimeException
继承自 Exception 的异常默认是受查异常
继承自 RuntimeException 的异常默认是非受查异常