1 面向对象基础
1.1 类的定义
基本信息
- 类的基本组成
- 成员变量(属性):
- 成员方法(行为):成员方法不含
static关键字
- 面向对象三大特征: 封装 、 继承 、 多态
```java
public class Student {
String name;
int age;
public void eat(){
} public void sleep(){System.out.println("Eat!");
}System.out.println("Sleep");
}
- **局部变量与成员变量的区别**- 定义的位置不同(局部变量在方法内部,成员变量在方法外部)- 作用范围不同(局部变量只在方法内部生效,成员变量在整个类上通用)- 默认值不同(局部变量没有默认值,成员变量若无赋值,会有默认初值,规则与数组默认值相同)- 内存位置不同(局部变量位于栈内存,成员变量位于堆内存)- 生命周期不一样(局部变量随着方法进栈而诞生,随着方法出栈而消失;成员变量随着对象创建而诞生,随着对象被垃圾回收而消失)<a name="QRUEO"></a>### private 关键字的作用- 用于保护成员变量- 一旦使用了 **private** 关键字,本类当中依然可以随意访问,但是超出本类范围之外则不可直接访问- 间接访问成员变量,则定义一对 **getter** 与 **setter** 方法- 对于基本类型中的 **boolean** ,其 **getter** 方法要写成 is`Xxx` 形式```javapublic class Person {String name;private int age;private boolean male;public void setMale(boolean b) {male = b;}public boolean isMale() {return male;}public void setAge(int num) {age = num;}public int getAge() {return age;}public void show() {System.out.println("姓名:" + name);System.out.println("年龄:" + age);}}
this 关键字的作用
当方法的局部变量和成员变量重名的时候,使用 this 将其区分
static 关键字
使用 static 关键字表明成员属性或成员方法直属于类,不单独属于任一对象
- 如果没有 static ,必须首先创建对象,通过对象再来使用它
- 否则,如果有 static , 则可以通过类名直接调用
- 本类当中定义的static方法在调用时可以省略类名称
- 注意: 静态方法不能直接访问非静态成员 ;静态方法中不可使用 this (静态的总是优先于非静态的)
静态代码块(典型用途:用来一次性对静态变量赋值)
public class Person{static{System.out.println("第一次使用此类时,静态代码块执行唯一的一次");}}
1.2 对象的创建及使用
基本概念
导包
import 包名称.类名称- 创建对象
类名称 对象名 = new 类名称() - 使用对象:使用运算符
.对于和当前类属于同一个包的情况,可以省略导包语句不写 只有
java.lang包下的内容不需要import
public class Student {String name;int age;public void eat() {System.out.println("Eat!");}public void sleep() {System.out.println("Sleep!");}public static void main(String[] args) {Student stu = new Student();stu.name = "Musou";stu.age = 24;System.out.println(stu.name + " " + stu.age);stu.eat();stu.sleep();}}
构造方法
- 专用于创建对象的方法
- 构造方法的名称必须和所在类名称完全一样
- 构造方法不需要写返回值类型,
void也不用写,构造方法同时也不可产生返回值 - 如果没有自己编写构造方法,编译器默认给出一个无参构造方法
- 若编写了自己的构造方法,编译器则不再给出默认构造方法
标准类(Java Bean)
一个标准的类通常由以下四个部分组成
- 所有的成员变量使用
private进行修饰 - 为每一个成员变量编写一对getter/setter方法
- 编写一个无参数的构造方法
-
1.3 API及其使用
1.4 匿名对象
只有对象,没有赋值
new 类名称()- 匿名对象只能使用唯一一次
匿名对象可以作为返回值与参数
new Person().name = "Musou";
2 继承
2.1 继承的基本概念
继承是多态的前提,没有继承,就没有多态
继承的格式
public class childClass extends parentClass{}Java继承的三个特点
三种重名的变量使用
- 局部变量:直接使用
num - 本类成员变量:
this.num - 父类成员变量:
super.num
- 局部变量:直接使用
- 成员变量的访问 :
Fu zi = new Zi()优先访问Fu类的成员变量 - 成员方法的访问 :
Fu zi = new Zi()优先访问Zi类的成员方法 构造方法的访问特点
重写:方法的名称一样,参数列表也一样
- 重载:方法的名称一样,但参数列表不一样
2.方法重写注意事项
- 必须保证父子类方法名称相同,参数列表也相同
- 使用
@Override写在方法前面用来检测是不是有效的正确覆盖重写 - 子类的返回值必须 小于等于 父类方法的返回值范围
子类方法的权限必须 大于等于 父类方法的权限修饰符(
public>protected> (default)>private) (注意,(default)代表关键字留空)2.4 super & this
1.super的三种用法
在子类的成员方法中,访问父类的成员变量
- 在子类的成员方法中,访问父类的成员方法
- 在子类的构造方法中,访问父类的构造方法
2.this的三种用法
- 在本类成员访问中,访问本类成员变量
- 在本类成员方法中,访问本类另一个成员方法
在本类的构造方法中,访问本类的另一个构造方法
抽象方法:方法本身无具体实现,但方法有其存在的必要性(如计算图形面积的方法,动物进食的方法)
public abstract class Animal {public abstract void eat(); //抽象方法}
如何创建抽象类和抽象方法
- 不能直接
new抽象类对象 - 必须用一个子类来继承抽象父类
- 子类必须覆盖重写抽象父类当中所有的抽象方法
- 不能直接
- 注意事项
3.1 接口的定义
接口定义的方法 :public interface 接口名称{}
接口包含的内容
- Java7: 常量;抽象方法
- Java8新增:默认方法;静态方法
-
3.2 接口的抽象方法
格式
public abstract 返回值类型 方法名称(参数列表);- 注意事项
- 抽象方法的修饰符是固定的
public abstract - 这两个关键字修饰符,可以选择性地省略(省略一个或全部)
- 抽象方法的修饰符是固定的
- 接口的使用
- 接口不能直接使用,必须有一个“实现类”来“实现”该接口:
public class 实现类名称 implements 接口名称{} - 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法
- 创建实现类的对象,进行使用
- 接口不能直接使用,必须有一个“实现类”来“实现”该接口:
注意事项
格式
public default 返回值类型(参数列表){方法体}- 接口当中的默认方法,可以解决接口升级的问题
注意事项
格式
public static 返回值类型 方法名称(参数列表){方法体};注意事项
应用场景:需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题,但是这个共有方法不应该让实现类使用,而应该是私有化的
- 普通私有方法
private 返回值类型 方法名称(参数列表){方法体} 静态私有方法
private static 返回值类型 方法名称(参数列表){方法体}3.6 接口的常量
格式
public static final 数据类型 常量名称 = 数据值;- 可以省略三个关键字修饰符
- 常量必须进行初始化
-
3.7 接口的继承
使用接口的注意事项
- 接口没有静态代码块和构造方法
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
- 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需覆盖重写一次即可
- 如果实现类没有覆盖重写所有接口中的所有抽象方法,那么实现类必须是一个抽象类
- 如果实现类所实现的多个接口中,存在冲突的默认方法,那么一定要对冲突的默认方法进行覆盖重写
- 一个类如果直接父类中的方法与接口中的默认方法冲突,那么优先使用父类的方法
接口与接口之间,是可以多继承的
代码中体现多态性的方法:父类引用指向子类对象
- 格式
父类名称 对象名 = new 子类名称()或者接口名称 对象名 = new 实现类名称() 使用多态的好处
直接通过对象名称访问成员变量:看等号左边是谁,就优先用谁,没有则向上找
间接通过成员方法访问成员变量:看该方法属于谁,就优先用谁,没有则向上找
4.3 多态成员方法
成员方法的访问规则:看
new的是谁,就优先用谁,没有则向上找区别
多态写法:
ParentClass obj = new ChildClass();- 含义:右侧创建一个子类对象,把它当作父类来看待使用
- 向上转型一定是安全的,因为小范围一定包含于大范围
弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容
向下转型
对象的向下转型,其实就是一个还原的动作
- 格式
ChildClass obj = (ChildClass)parentObj; - 含义:将父类对象还原成为子类对象
-
类型判断
使用
instanceof关键字格式
对象名 instanceof 类名称会返回一个布尔值5 内部类
5.1 final关键字
修饰类
public final class 类名称{}- 太监类,当前这个类不能有任何子类
- 修饰成员变量
- 由于成员变量具有默认值,所以使用
final后必须手动赋值 - 要么直接赋值,要么通过构造方法赋值
- 由于成员变量具有默认值,所以使用
- 修饰成员方法
修饰符 final 返回值类型 方法名称(参数列表){}- 该方法不可被覆盖重写
修饰局部变量
权限修饰符小结
如果一个事物的内部包含另一个事物,那么称一个类包含一个内部类
内部类分为
成员内部类的定义
public class Body{public class Heart{public void beat(){System.out.println("My heart beats.");}...}public void methodBody(){Heart heart = new Heart();heart.beat();}...}
注意:内用外,随意访问;外用内,必须借助内部类对象
成员内部类的使用
public class Main(){public static void main(String[] args){//间接方式:在外部类的方法中使用内部类,然后main只是调用外部类的方法Body body = new Body();body.methodBody();//直接方式Body.Heart heart = new Body().new Heart();heart.beat();}}
内部类的同名变量访问 ```java public class Outer { int num = 30; public class Inner{
int num = 20;public void method(){int num = 10;System.out.println(num); // 局部变量,就近原则System.out.println(this.num); // 使用内部类成员变量System.out.println(Outer.this.num); // 使用外部类成员变量}
} }
<a name="ahgRq"></a>### 局部内部类```javapublic class Outer {public void methodOuter(){class LocalInner{int num = 10;public void methodInner(){System.out.println(num);}}LocalInner inner = new LocalInner();inner.methodInner();}}
- 局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】
从Java8开始,只要局部变量事实不变,那么
final关键字可以省略(跟生命周期相关)匿名内部类
匿名内部类也是局部内部类中的一种
如果接口的实现类(或者父类的子类)只需要使用唯一的一次,那么可以省略掉该类的定义,而改为使用 匿名内部类
匿名内部类的定义格式
//接口名称 对象名 = new 接口名称(){// 覆盖重写所有的抽象方法//}MyInterface obj = new MyInterface(){@Overridepublic void method(){System.out.println("匿名内部类");}};
6 包装类
6.1 概念
包装类 :基本类型没有对应的方法来操作基本类型的数据,因此可以使用类进行包装,在类中定义操作基本类型的方法
包装规则
装箱 :从基本类型转换为对应的包装类对象
- 拆箱 :从包装类对象转换为对应的基本类型 ```java //装箱 Integer i = new Integer(4); //使用构造方法(已过时) Integer j = new Integer(“100”); //使用构造方法 Integer k = Integer.valueOf(4); //使用静态方法 Integer w = Integer.valueOf(“100”);
//拆箱 int ii = i.intValue(); int jj = j.intValue();
> 从Java5开始,装箱与拆箱动作可以自动完成<a name="anr18"></a>##<a name="tvA1v"></a>## 6.3 基本类型与字符串相互转换- 基本类型 ===> 字符串(String)- 基本类型值 + ""- **包装类** 的静态方法 `toString` : `static String toString(int i)`- **String类** 的静态方法 `valueOf` : `static String valueOf(int i)`- 字符串 ===> 基本类型- 使用包装类的静态方法parseXXX: `static double parseDouble(String s)`<a name="AcMji"></a># 7 泛型> ArrayList集合在定义时不知道集合中会存储什么类型的数据,此时可以使用使用泛型**使用泛型的好处**- 集合若不使用泛型,默认的类型是 `Object` 类型,可以存储任意类型的数据,这样不安全,会引发异常(例如不能使用子类特有的方法,必须得向下转型,很麻烦)- 使用泛型,避免了类型转换的麻烦- 使用反省,把运行期异常提升到了编译期<a name="FpJoz"></a>## 7.1 含泛型的类```javapublic class GenericClalss<E>{private E name;public E getName(){return name;}public void setName(E name){this.name = name;}}
7.2 含泛型的方法
- 泛型定义在方法的修饰符和返回值类型之间 ```java package Generic;
public class GenericMethod {
public void method02(S s){
System.out.println(s);
}
}
<a name="XY37m"></a>## 7.3 含泛型的接口```javapackage Generic;public interface GenericInterface<T>{public abstract void method01(T i);}
- 第一种实现方式 ```java package Generic;
public class GenericInterfaceImpl1 implements GenericInterface
- 第二种实现方式```javapackage Generic;public class GenericInterfaceImpl2<I> implements GenericInterface<I>{@Overridepublic void method01(I i) {System.out.println(i);}}
7.4 泛型通配符
- 不知道使用什么类型来接收时,可以使用?, 其中?表示通配符
- 此时只能接收数据,不能往该集合中存储数据
- 泛型没有继承概念,所以无法使用向上转型来接收参数 ```java package API;
import java.util.ArrayList; import java.util.Iterator;
public class DemoAsterisk {
public static void main(String[] args) {
ArrayList
- **泛型的上限限定** : `? extends E` 代表使用的泛型只能是E类型的子类/本身- **泛型的下限限定** : `? super E` 代表使用的泛型只能是E类型的父类/本身```javapackage API;import java.util.ArrayList;import java.util.Collection;public class DemoAsterisk2 {public static void main(String[] args) {Collection<Integer> list1 = new ArrayList<>();Collection<String> list2 = new ArrayList<>();Collection<Number> list3 = new ArrayList<>();Collection<Object> list4 = new ArrayList<>();getElement1(list1);getElement1(list2); //报错getElement1(list3);getElement1(list4); //报错getElement2(list1); //报错getElement2(list2); //报错getElement2(list3);getElement2(list4);}private static void getElement1(Collection<? extends Number> list) {}private static void getElement2(Collection<? super Number> list) {}}
