面向对象
面向对象是一种思想,其他编程语言也有这个思想
面向对象的三大特征:封装,继承,多态
封装
隐藏具体代码的实现细节,提供公共的访问接口
作用:
提高代码的复用性
提高代码的安全性
对类中的属性进行封装,提供对外访问的方法
属性私有化 private 类型 变量 = 值
public class Student {
private String name; //用private关键字私有化属性,外部无法访问
private int age;
public String getName() { //对外提供访问属性的方法
return name;
}
public void setName(String name) {//对外提供修改属性的方法
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
权限修饰符:
权限修饰符可以修饰类,方法,成员变量
private、default、protected、public的区别:
private 修饰的只能在当前类中使用
default 默认的修饰符,当前类和当前包下都能访问,子类无法访问,其他位置无法访问
protected:当前类及其子类和当前包下都能访问,其他位置无法访问
public: 公共的,任意访问
权限修饰符在所有修饰符之前
abstract不能和private/static/final一起使用
能修饰类的只有public(最常用),默认的,final,abstract
this关键字
当一个类创建对象后,对象内部的this关键字就表示这个对象
或者 Student st = new Student()中 , this 就是这个st对象引用
可以在类的内部用 this.属性 来调用这个类中的成员变量
对象是无法调用自身的局部变量,所以可以用 this.属性 来区分成员变量与局部变量
1.this表示当前当前对象
2.this可以指定同名的成员变量区别与局部变量
3.引用构造方法
public class Student {
xxxx 成员变量name
xxxx成员变量age
public void tes() {
int age = 23;//局部变量
System.out.println(this.age);//引用成员变量
}
}
//调用方法
st.setAge(25); //为成员变量赋值
st.setName("gg");
st.tes();//25
继承
一个类通过extends关键字来复用另一个类的属性和方法
java只能单继承,不能多继承,可以多层继承,所有类都直接或间接继承了object类
特性:
1.子类拥有父类非 private 的属性、方法
2.子类可以拥有自己的属性和方法,即子类进行功能的扩展
3.子类可以用同名的方式来重写父类的方法
4.Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,
多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,
所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,
这是 Java 继承区别于 C++ 继承的一个特性
5.提高了类之间的耦合性
格式:
class 子类 extends 父类{
}
一个类只能有一个父类
一个父类可以有多个子类
通过super关键字在子类中来实现对父类成员的访问,用来引用当前对象的父类
通过子类对象调用成员属性/方法时,如果子类有酒调用子类的,子类没有就去父类调用
public class Person {
String name = "father";
}
public class Son extends Person {
String name = "son";
public void show() {
System.out.println("调用子类属性" + name);
System.out.println("调用父类属性" + super.name);
}
}
public static void main(String[] args) {
Son son = new Son();
son.show();
}
方法重写
子类继承父类后,在子类中重新定义与父类方法名一致,
返回值类型一致(可以为返回值类型的子类型),参数一致的方法
子类重写的方法不能使用比父类中被重写的方法更严格的访问权限
private < default < protected < public
子类重写的方法不能声明抛出比父类中被重写方法范围更大的异常类型
重写是子类对所继承父类相同方法的一种更改,父类定义方法规则,子类来实现这个规则
public class Person {
String name = "father";
public void show() {
System.out.println("父类方法");
}
}
public class Son extends Person {
String name = "son";
public void show() {//重写父类方法
System.out.println("子类方法");
}
}
Son son = new Son();
son.show();
父类中私有方法不能被重写
父类静态方法,子类也必须通过静态方法进行重写
父类被final修饰的方法不能被重写
方法重写和方法重载的区别
Overload: 重载,在一个类中,可以定义多个同名的方法,
但形参列表不完全相同;跟返回值无关
Override: 重写,在子类中,可以定义跟父类一模一样的方法
(返回值类型、方法名、形参列表完全相同),
这时子类的方法会覆盖父类中同名的方法
抽象类和抽象方法
用abstract修饰的类,即抽象类;用abstract修饰的方法,即抽象方法
有抽象方法的类一定是抽象类
抽象类可以没有抽象方法
抽象类不能实例化
抽象类可以有具体的方法和属性
抽象方法不能有方法的主体
抽象类不能用final来修饰
抽象类是用来继承的
一个普通类继承了抽象类,必须重写其中所有的抽象方法
如果子类也是一个抽象类,并不要求一定重写父类方法
抽象类更像是一种模板,规定了子类一定要实现的方法
抽象类的存在就是为了不让人为的实例化这个类,同时让普通子类去实现所有的抽象方法
public abstract class AbstractClass { //抽象类
public abstract void show();//抽象方法
}
public class Son extends AbstractClass { //普通类继承抽象类
@Override //表示重写方法的注解
public void show() {
System.out.println("子类重写的方法");
}
}
Son son = new Son();
son.show();
final关键字
final可以修饰类,方法,变量
修饰类:该类不能继承
修饰方法:子类无法重写,可以继承
修饰变量:final修饰的变量是常量,在类的加载完成时(在创建对象之前)就已经赋值,只能赋值一次
final修饰的引用类型变量,仅仅保证地址值不变,而地址值的内容可以改变
final 修饰变量赋值的两种方式 1.final int a = 9 2. 利用构造方法赋值
接口
用Interface修饰的类,比抽象类更抽象的类
接口是一种特殊的抽象类
所以接口也是不能实例化的
接口中只能有常量(默认是静态,public static final)和(public abstract)抽象方法
接口是用来实现的
接口与接口之间只能继承,可以多继承;不能实现
类与类的关系 :继承,只能单继承,可以多层继承
类与接口 :实现,可以单实现或多实现(解决普通类无法多继承的问题)
接口与接口 :可以单继承或多继承,Java有多继承(限于接口)
接口是解决Java无法使用多继承的一种手段
格式:
interface 修饰接口类
class 类名 implements 接口名{} 实现接口类
public interface MyInterface {// 定义接口类
public abstract void funciton();// 抽象方法
}
//实现接口类
public class MyInterfaceImpl implements MyInterface {
@Override
public void funciton() { // 实现接口中的抽象方法
System.out.println("实现接口中的方法");
}
}
//调用
MyInterfaceImpl my = new MyInterfaceImpl();
my.funciton();
//接口1 继承 接口2,普通类1实现接口1,就必须实现接口1和接口2中所有的抽象方法
接口和抽象类的语法区别:
1.接口不能有构造方法,抽象类可以有。
2.接口不能有方法体,抽象类可以有。
3.接口不能有静态方法,抽象类可以有。
4.在接口中凡是变量必须是public static final,而在抽象类中没有要求
多态
多态指的是一类事物有多种形态
多态指父类引用指向子类对象
class Father{...}
class Son extends Father{...}
多态: Father fa = new Son()
1.多态是在继承的基础上延伸的
2.子类要有重写父类的方法
3.父类引用指向子类对象
多态中成员特点
父类引用.成员方法()
编译期检查父类是否含有这个方法,没有会报错;运行期会去调用子类中的重写方法,子类没有就调用父类方法
父类引用.成员属性
编译期检查父类是否有这个属性,没有会报错;运行期去调用父类的属性,无论子类是否有同名属性
public class Person {
String name = "father";
public void show() {
System.out.println("父类方法");
}
}
public class Son extends Person {
@Override
public void show() {
System.out.println("子类重写的方法");
}
}
//普通类作为父类
Person son = new Son();
son.show(); //子类重写的方法
//抽象类作为父类 public class Son extends Person
Person son = new Son();
son.show(); //子类重写的方法
//接口类作为父类 public class Son implements Person
Person son = new Son();
son.show(); //子类重写的方法
1.成员变量:编译看父类,运行看父类,没有就报错
2.构造方法:创建子类对象时候,访问父亲的构造方法,对父类数据进行初始化
3.成员方法:编译看父类,运行看子类,没有就报错
4.静态方法:编译看父类,运行看父类,静态和类相关,算不上重写
因为成员方法存在重写,所以运行看子类
instanceof
判断一个对象的引用是否是指定的类型
对象引用 instanceof 类名
Person son = new Son();
son.show();
boolean b = son instanceof Person;
boolean b1 = son instanceof Son;
System.out.println(b);// true
System.out.println(b1);// true
多态的向上向下转型
向上转型 父类 父类对象 = 子类实例
向上转型 子类 子类对象 = (子类)父类实例
Person son = new Son(); // 向上转型
son.show();
if (son instanceof Son) {
Son person = (Son) son;// 向下转型
}
构造方法
在对象创建后(new 对象())对其进行初始化的方法,为对象的属性初始化值,在一个对象存在期间只执行一次
格式:
修饰符 构造方法名(参数列表){
}
构造方法没有返回值,包括void
构造方法名与类名一致
构造方法没有具体的返回值
构造方法不能被 static、final、synchronized、abstract 和 native修饰
构造方法不能被子类继承
每个类可以具有多个构造方法,但要求它们各自包含不同的方法参数
每个类都有构造方法,不写有默认的无参构造方法
写了有参的构造方法要手动加上无参的构造方法
public class Animal {
public Animal() {
System.out.println("无参构造器");
}
}
main():
Animal an = new Animal();// 无参构造器
Animal an2 = new Animal();// 无参构造器
//每一次new都会运行这个类的无参构造器
//可以利用构造方法来完成属性的初始化
public class Animal {
String name;
int age;
public Animal() {
this("张三", 23);//调用自身有参构造方法
System.out.println("无参构造器");
}
public Animal(String name, int age) {// 初始化
this.name = name;//初始化自身属性
this.age = age;
System.out.println("有参构造器");
}
}
main():
Animal an = new Animal();// 无参构造器
Animal an2 = new Animal("张三", 23);// 有参构造器
System.out.println(an2.getAge());// 23
super关键字
1.在子类中引用父类的成员属性/方法
2.在子类中引用同名的父类属性/方法
3.在子类中引用父类构造方法
子类构造方法无论重载多少个第一行默认就是super()调用父类无参构造方法
this()和super()都指的是对象,所以,均不可以在static环境中使用。
包括:static变量,static方法,static语句块
super()和this()均需放在构造方法内第一行
this和super不能同时出现在一个构造函数里面
public class Animal {
public Animal() {
System.out.println("Animal无参构造器");
}
}
public class Dog extends Animal {
public Dog() {
super();
System.out.println("Dog");
}
}
main():
Dog dog = new Dog();
//Animal无参构造器
//Dog
static关键字
static可以修饰变量,方法
修饰变量,变量就是静态变量,可以被当前类所有对象共享,可以不创建对象,直接以类名.静态属性名调用
修饰方法,就是静态方法,可以直接以类名.静态方法名调用
内存中,静态成员是优于非静态成员存在的,所以静态成员内部无法调用非静态成员
静态属于类,不属于对象
public class Dog {
static int i;
public Dog() {
super();
i = 10;
}
}
Test.class
main():
System.out.println(Dog.i);//0
Dog dog = new Dog();
System.out.println(Dog.i);//10
//将Test.class加载进方法区,加载Test的静态成员main方法至静态区(数据共享区)
//加载Dog.class进方法区,加载Dog的静态成员i,默认值为0
//开始运行main方法,JVM到静态区将main方法复制一份压栈运行
//去静态区找到Dog类的静态属性i然后输出
//创建Dog对象,运行无参构造器,在堆中开辟内存空间
//为静态变量赋值
匿名对象
普通对象 Dog dog = new Dog(); 可以多次使用
匿名对象 new Dog(); 只能使用一次就会被回收
匿名对象可以调用属性/方法
public class Dog {
String name;
}
main():
new Dog().name = "张三"; //创建一个对象并赋值而后销毁
new Dog().name = "李四"; //又创建一个对象再次赋值而后再次销毁
内部类
一个类中再次定义类,被定义的类就是内部类,可以使用修饰符,可以继承,可以实现接口
根据定义位置的不同分为成员内部类和局部内部类
成员内部类
成员内部类可以调用外部类所有的成员属性和方法(包括private和静态成员)
外部类调用内部类属性和方法,需要创建内部类对象
外部想调用内部类属性和方法,必须创建内部类的对象,内部类依托于外部类存在
所有要先创建外部类对象,再创建内部类对象
外部类.内部类 对象名 = new 外部类().new 内部类();
public class Dog {
static int i = 10; //静态属性
private String name = "环境";//同名私有属性
class Inside {
String name = "fhj";//同名属性
public void show() {
System.out.println(i);
System.out.println(name);// 调用内部类属性
System.out.println(Dog.this.name);// 调用外部类同名属性
}
}
}
main():
//外部创建内部类实例
Dog.Inside dog = new Dog().new Inside();
dog.show();
//10
//fhj
//环境
局部内部类
局部内部类就像是方法里面的一个局部变量一样,
是不能有public、protected、private以及static修饰符的
局部内部类一般只在方法体内有效
局部内部类访问局部变量时,其局部变量必须用final修饰,
因为局部变量随方法的调用而调用,调动结束后消失
而堆内存中的内容不会立即消失
一般直接在方法体中定义,创建对象,调用
public class Dog {
static int i = 10;
private String name = "环境";
public void test() {
class Inner { //局部内部类
public void show() {
System.out.println(name);
System.out.println("局部内部类");
}
}
Inner in = new Inner();//局部内部类只在方法体内有效
in.show();
}
}
//调用
main():
Dog dog = new Dog();
dog.test();
匿名内部类
匿名内部类是最常用的内部类
匿名内部类也是不能有访问修饰符和static修饰符的
匿名内部类是唯一一种没有构造器的类,大部分匿名内部类用于接口回调
public interface Interface {
public abstract void show();
}
main():
Interface in = new Interface() {//创建接口的实现类对象
@Override
public void show() {
System.out.println("匿名内部类的方法");
}
};
in.show();//并调用重写方法
静态内部类
静态内部类的特性和静态成员与内部类集合体
不能调用非静态的属性和方法
public class Dog {
static int i = 10;
static class Inner {
public void show() {
System.out.println(i);
System.out.println("静态内部类");
}
}
}
main():
Dog.Inner dog = new Dog.Inner();
dog.show();
代码块
代码块分为局部代码块,构造代码块,静态代码块
局部代码块:对象调用才会执行的代码块,定义在方法体内部
构造代码块:对象每一次创建(new),都会执行一次,时机早于构造方法,在定义在类体中
静态代码块:随着对象创建(new)而执行,只会执行一次,即使创建多个对象也只会执行一次
时机优先与构造代码块,定义在类体中
代码块中可以限制其中变量的生命周期与作用域
public class Dog {
static {
System.out.println("静态代码块");
}
{
System.out.println("构造代码块");
}
public Dog() {
System.out.println("构造方法");
}
public void show() {
{
System.out.println("局部代码块");
}
}
}
main():
Dog dog = new Dog();
dog.show();
//静态代码块
//构造代码块
//构造方法
//局部代码块
类的初始化示例
public class A {
B b = new B();
A() {
System.out.println("A");
}
}
public class B {
B() {
System.out.println("B");
}
}
public class C extends A {
B b = new B();
C() {
System.out.println("C");
}
public static void main(String[] args) {
C c = new C();
}
}
//B
//A
//B
//C
//构造方法第一行默认super()
//先初始化父类数据,再初始化子类数据,与代码顺序无关
类,接口都可以作为方法的参数,返回值