面向对象
1)类
[修饰符] class 类名 [extends 父类名] [implements 接口名]{
//类体,包括类的成员变量和成员方法
}
1.1 成员变量
语法格式:
[修饰符] 数据类型 变量名 [ =值]
private String name;
private int age = 18;
1.2 成员方法
语法格式:
[修饰符] [返回值类型] 方法名 ([参数类型 参数名1,参数类型 参数名2,……]) {
//方法体
……
return 返回值; //返回值类型为void时,return及返回值可以省略
}
public class Person{
int age;
void speak(){
System.out.println("我今年"+age+"岁了!")
}
}
Java中定义在类中的变量被称为成员变量,定义在方法中的变量被称为局部变量。
1.3 访问控制符
- private(当前类访问级别):类的成员被其修饰,则此成员只能被该类的其他成员访问,其他类无法直接访问。
- default(包访问级别):如果一个类或者类的成员不使用任何访问修饰符,则称它为默认访问级别,这个类或者类的成员只能被本包中的其他类访问。
- protected(子类访问级别):一个类的成员被其修饰,那么这个成员既能被同一包的其他类访问,也能被不同包下该类的子类访问。
- public(公共访问级别):这是一个最宽松的访问级别,如果一个类或者类的成员被其修饰,那么这个类或者类的成员能被所有的类访问,不管访问类与被访问类是否在一个包。
2)对象
语法格式:
类名 对象名称 = new 类名();
Person p = new Person();
Java中内存分为两种,即栈内存和堆内存。其中栈内存用于存放基本类型的变量和对象的引用变量(如 Person),堆内存用于存放由new创建的对象和数组
2.1 对象的访问
语法格式:
对象引用.对象成员
public class Example01{
public static void main(String[] args){
Person p1 = new Person;
Person p2 = new Person;
p1.age = 18;
p1.speak(); //结果:我今年18岁了!
p2.speak(); //结果:我今年0岁了!
}
}
语法格式:
new 类名().对象成员
通过new关键字创建实例对象的同时访问对象的某个成员,并且在创建后只能访问其中某一个成员,而不能像对象引用那样可以访问多个对象成员。
当没有任何变量引用这个对象时,它将成为垃圾对象,不能再被使用。
3)封装
类的封装:
指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类所提供的方法来实现对内部信息的操作访问。
class Person {
//private实现成员封装
private String name;
private int age;
//获取、设置成员变量
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
//判断数值,设置年龄
if (age <= 0) {
System.out.println("您输入的年龄不正确!");
} else {
this.age = age;
}
}
public void setName(String name) {
this.name = name;
}
public void speak() {
System.out.println("我叫" + name + ",今年" + age);
}
}
public class TestPerson {
public static void main(String[] args) {
Person p = new Person();
p.setName("张三");
p.setAge(-18);
p.speak();
}
}
4)重载
重载:同一个类中定义多个名称相同,但是参数的类型或个数不同的方法。
方法的重载与返回值类型无关
public class Example06 {
public static int add(int x, int y) {
return x + y;
}
public static int add(int x, int y, int z) {
return x + y + z;
}
public static double add(double x, double y) {
return x + y;
}
public static void main(String[] args) {
//根据参数类型或个数调用
int sum1 = add(1, 2);
int sum2 = add(1, 2, 3);
double sum3 = add(0.1, 0.2);
}
}
5)递归
方法的递归:指在一个方法的内部调用自身的过程。
递归必须要有结束条件,不然会陷入无限递归状态
public class Example06 {
public static int getSum(int x) {
if (x == 1) {
return 1;
}
int temp = getSum(x - 1);
return temp + x;
}
public static void main(String[] args) {
//递归方法,计算1~4的和
int sum = getSum(4);
}
}
6)构造方法
构造方法是会在类实例化对象时自动调用。
语法格式:
[修饰符] 方法体 ([参数列表]){
//方法体
}
- 方法名与类名相同
- 在方法名的前面没有返回值类型声明
- 在方法中不能使用return语句返回一个值,但是可以单独写return语句来作为方法的结束
class Person {
public Person() {
System.out.println("无参构造方法!");
}
}
public class TestPerson {
public static void main(String[] args) {
Person p = new Person();
}
}
class Person {
int age;
//有参构造方法
public Person(int a) {
age = a;
}
public void speak() {
System.out.println("我今年" + age + "岁了!");
}
}
public class TestPerson {
public static void main(String[] args) {
Person p = new Person(18);
p.speak();
}
}
7.1 构造方法的重载
-
在一个类中可以定义多个构造方法,只要每个构造方法的参数类型或者参数个数不同即可。
-
Java中每一个类都至少有一个构造方法,如果没有显式地定义构造方法,系统会自动为该类创建一个默认的构造方法,但是这个构造方法没有参数,也没有方法体,即什么也做不了。
-
一个类中如果定义了有参的构造方法,最好再定义一个无参的构造方法。
-
构造方法如果被private修饰,该构造方法就只能被当前类访问,无法在外部类访问,也就无法通过该私有构造方法来创建对象。
7)继承
类的继承:指一个现有的类基础上去构建一个新的类,构建出来的新类被称为子类,现有类被称为父类或基类,子类会自动拥有父类所有可继承的属性和方法。
语法格式:
[修饰符] class 子类名 extends 父类名{
//程序核心代码
}
注意:
- 在Java中,类只支持单继承,不允许多重继承,也就是说一个类只能有一个直接父类
- 多个类可以继承同一个父类
- 在Java中,多层继承时可以的,即一个类的父类可以再去继承另外的父类
- 再Java中,子类和父类是一个相对概念,也就是说一个类是某个父类的同时,也可能是另一个类的子类
7.1 重写父类方法
- 在子类中对继承的方法进行一些修改,即对父类的方法进行重写。
- 子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
注意:
子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限。父类是public,子类重写时不能用private。
8)Object类
Object类是所有类的父类,即每个类直接或间接继承该类,因此通常被称为超类、基类或根类。
- getClass().getName()代表返回对象所属类的类名,即包名+类名的全限定名称。
- hashCode()代表返回该对象的哈希值。
- Integer.toHexString(hashCode())代表将对象的哈希值用十六进制表示。
9)多态
多态:指不同类的对象在调用同一个方法所呈现出的多种不同行为。
9.1 向上转型
Animal an1 = new Cat();
//将Cat类对象当作Animal类型使用
将子类对象当作父类使用,此时不能通过父类变量去调用子类特有的方法。
9.2 向下转型
必须转换为本质类型
Animal an1 = new Dog();
Dog dog = (Dog)an1;
instanceof:
用于判断一个对象是否为某一类(或接口)的实例或者子类实例。
10)抽象类
抽象方法必须使用abstract关键字用来修饰,并且在定义方法时不需要实现方法体。
当一个类包含了抽象方法,那么该类也必须使用abstract关键字修饰,该类就是抽象类。
语法格式:
//定义抽象类
[修饰符] abstract class 类名{
//定义抽象方法
[修饰符] abstract 方法返回值类型 方法名 ([参数列表]);
}
抽象方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法
抽象类不可以被实例化,因为抽象类中有可能有抽象方法,抽象方法是没有方法体的,不可以被调用
为抽象类创建一个子类,在子类中实现抽象类中的抽象方法
public abstract void shout();
子类实现了父类的抽象方法后,已经可以正常进行实例化操作,通过实例化的对象即可调用实现的方法。
11)接口
如果一个抽象类中的所有方法都是抽象的,则可以将这个类定义为接口,接口是一种特殊的抽象类,它不能包含普通方法,其内部的所有方法都是抽象方法。
JDK8中,接口中除了抽象方法外,还可以有默认方法(default)和静态方法([类方法]、[static]),并且这两种方法都允许有方法体。
语法格式:
[修饰符] interface 接口名 [extends 父接口1,父接口2,……]{
[pubilc] [static] [final] 常量类型 常量名 = 常量值;
[pubilc] [abstract] 方法返回值类型 方法的名([参数列表]);
[pubilc] default 方法返回值类型 方法的名([参数列表]){
//默认方法的方法体
}
[pubilc] static 方法返回值类型 方法名([参数列表]){
//类方法的方法体
}
}
接口特点总结:
- 接口可以继承多个父接口
- 在接口内部可以定义多个常量和抽象方法,定义常量时必须进行初始化赋值,定义默认方法和静态方法时,可以有方法体
- 静态方法可以通过“接口名.方法名”的形式调用,而抽象方法和默认方法只能通过接口实现类的实例对象类来调用。
- 当一个类实现接口时,如果这个类是抽象类,只需要实现接口中的部分抽象方法即可,否则需要实现接口中所有抽象方法。
- 一个类可以继承另一个类的同时实现多个接口,并且多个接口之间需要使用英文(,)分隔。
- 接口的实现类,必须实现接口中的所有抽象方法,否则会编译报错。
接口实现类语法格式:
[修饰符] class 类名 [extends 父类名] [implements 接口1,接口2,……]{
……
}
12)关键字
12.1 this关键字
1、通过this关键字调用成员变量,解决与局部变量名称冲突问题。
class Person {
int age;
public Person(int age) {
this.age = age;
}
}
2、通过this关键字调用成员方法
class Person {
public void run() {
}
public void speak() {
//此处关键字可以省略不写
this.run();
}
}
3、通过this关键字调用构造方法
可以在一个构造方法中使用 “this([参数1,参数2,····])” 的形式调用其他构造方法。
class Person {
int age;
public Person() {
}
public Person(int age) {
this();
}
}
注意:
- 只能在构造方法使用this调用其他构造方法,不能在其他成员方法中使用
- 在构造方法中,使用this调用构造方法的语句必须是该方法的第一条执行语句,且只能出现一次
- 不能在一个类的两个构造方法中使用this互相调用
12.2 super关键字
子类重写父类方法后,子类对象将无法直接访问父类被重写方法。
super关键字用于访问父类成员,例如父类的成员变量、成员方法、构造方法。
1、使用super关键字调用父类的成员变量和成员方法。
super.成员变量
super.成员方法([参数1,参数2,……])
2、使用super关键字调用父类的构造方法。
super([参数1,参数2,……])
注意:
通过super调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次,否则程序在编译期间就会报错。
子类在实例化时默认调用了父类无参的构造方法。
在定义一个类时,如果没有特殊需求,当定义了有参构造方法后,尽量在类中显式地定义一个无参构造方法,这样可以避免该类被继承时出现错误。
12.3 static关键字
12.3.1 静态变量
某些特定的数据在内存中只有一份,而且能够被一个类的所有实例对象所共享
访问静态变量语法格式:
类名.变量名
实例对象名.变量名
static关键字只能用来修饰成员变量,不能用来修饰局部变量
12.3.2 静态方法
访问静态方法语法格式:
类名.方法
实例对象名.方法
class Person {
public static void say() {
System.out.println("静态方法!");
}
}
public class TestPerson {
public static void main(String[] args) {
//类名.方法
Person.say();
Person p = new Person();
//实例对象名.方法
p.say();
}
}
注意:在静态方法中只能访问用static修饰的成员,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建对象
12.3.3 静态代码块
语法格式:
static{
……
}
当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块也执行一次。
12.4 final关键字
含义:”不可更改“、“最终”
特征:
- final修饰的类不能被继承
- final修饰的方法不能被子类重写
- final修饰的变量(成员变量和局部变量)时常量,只能赋值一次,一旦被赋值,其值不能改变。
13)内部类
13.1 成员内部类
- 在类中定义的类,被称为成员内部类。
- 成员内部类可以访问外部类所有成员。
- 外部类也可以访问所有内部类的变量和方法。
通过外部类对象创建内部类对象语法格式:
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
13.2 局部内部类
定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,其范围只限于方法内部。
局部内部类可以访问外部类所有成员变量和方法。
局部类中的变量和方法只能在包含该局部内部类的方法中进行访问。
13.3 静态内部类
- 使用static关键字修饰的成员内部类。
- 静态内部类中只能访问外部类的静态成员。
- 通过外部类访问静态内部成员时,可以跳过外部类从而直接通过内部类访问静态内部类成员。
创建静态内部类对象语法格式:
外部类名.静态内部类名 变量名 = new 外部类名.静态内部类名();
13.4 匿名内部类
匿名内部类其实就是没有名称的内部类,在调用包含接口类型参数的方法时,简化代码,不会创建一个接口实现类作为方法参数传入,而是直接通过匿名内部类的形式传入一个接口类型参数,在匿名内部类中直接完成方法的实现。
创建匿名内部类语法格式:
new 父接口(){
//匿名内部类实现部分
}
14)异常
- Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽的错位,是比较严重的。
- Exception类称为异常类,它表示程序本身可以处理的错误。
14.1 编译时异常
RuntimeException类及其子类除外,其他子类都是编译时异常。
- 使用try……catch语句对异常进行捕获处理。
- 使用throws关键字声明抛出异常,让调用者对其处理。
14.2 运行时异常
RuntimeException类及其子类都是运行时异常。
创建静态内部类对象语法格式:
外部类名.静态内部类名 变量名 = new 外部类名.静态内部类名();