目录
一、引言
面向对象三大特性:封装、继承、多态。
二、封装
2.1封装的必要性
- 在对象的外部,为对象的属性赋值,可能存在非法数据的录入。
- 就目前的技术而言,并没有办法对属性的赋值加以控制。
2.2什么是封装
概念:尽可能隐藏对象的内部实现细节,控制对象的修改及访问的权限。
访问修饰符:private (可将属性修饰为私有,仅本类可见)
私有属性在类的外部不可访问
2.3公共访问方法
提供公共访问方法,以保证数据的正常录入。
命名规范:
赋值:setXXX() //使用方法参数实现赋值
取值:getXXX() //使用方法返回值实现取值
代码展示:
在公共的访问方法内部,添加逻辑判断,进而过滤掉非法数据,以保证数据安全。
user类
public class User {
private String name;
private int age;
//set设置属性 get获取属性 方法
//快捷方式:alt+insert 或者右击选Generate
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
//过滤非法数据
if(age>150||age<0){
this.age=18;
}else{
this.age = age;
}
}
}
TestUser类
public class TestUser {
public static void main(String[] args) {
User user=new User();
//user.name="jack";
//user.age=200000;
user.setName("rose");
user.setAge(20);
System.out.println(user.getName());
System.out.println(user.getAge());
}
}
2.5 JavaBean 设计
类:实体类 JavaBean。
JavaBean 分为两种:
1、数据承载Bean
2、业务逻辑Bean
数据承载Bean的要求
1、私有化属性
2、对外提供公共的set、get方法
3、提供有参无参构造
代码展示:
public class Product {
private int id;//唯一标识
private String name;
private double price;
public Product(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Product() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
三、继承
3.1程序中的继承
程序中的继承,是类与类之间特征和行为的一种赠与或获得。
两个类之间的继承关系,必须满足“is a”的关系。
功能越精细,重合点越多,越接近直接父类。
功能越粗略,重合点越少,越接近Object类。(万物皆对象的概念)
3.2父类的抽象
可根据程序需要使用到的多个具体类,进行共性抽取,进而定义父类
在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用。
代码展示:
public class Animal {
String name;
int age;
String color;
public void eat(){
System.out.println("吃");
}
public void sleep(){
System.out.println("睡");
}
}
public class Dog extends Animal{//继承自Animal
//定义子类独有的属性
String hobby;
//定义子类独有的方法
public void swimming(){
System.out.println("会游泳");
}
}
public class Test {
public static void main(String[] args) {
//创建Dog类的对象
Dog dog=new Dog();
//dog对象调用父类的属性(从父类继承而来)
dog.name="旺财";
dog.age=2;
dog.color="白色";
//dog对象调用子类独有的属性(自己定义的)
dog.hobby="吃东西";
System.out.println(dog.name);
System.out.println(dog.age);
System.out.println(dog.color);
System.out.println(dog.hobby);
//dog对象调用父类的方法(从父类继承而来)
dog.eat();
dog.sleep();
//dog对象调用子类独有的方法(自己定义的)
dog.swimming();
}
3.3继承
继承概念:类与类之间属性和方法的赠与和获得
继承作用:减少代码的冗余,提高代码的复用性。
继承语法:子类 extends 父类
3.4继承的特点
1、子类继承父类,可以继承父类中的属性和方法
2、子类可以拥有自己独有的属性和方法
3、单继承,即在java中一个子类只能继承一个父类。但是一个父类可以拥有多个子类
4、多重继承,即一个父类还可以继承另外一个类。java中最大的父类的是Object(如果一个没 有显示的写出extends 父类,默认就是Object子类)
3.5不可继承
1、构造方法不能被继承
2、父类的私有属性不能被继承
3、父类中使用默认的修饰符的修饰的属性和方法在不同包的子类中不能被继承
四、访问修饰符
- private私有的
- default缺省的、默认的、友好的
- protected 受保护的
- public 公开的
访问修饰符:可以修饰属性,方法,内部类
五、方法重写
5.1 方法的重写/覆盖
子类中有与父类相同签名的方法称之为方法重写
重写的特点:
相同签名 : 方法名相同、参数相同、返回值相同、子类访问修饰符要比父类更宽泛
重写的作用:
因为父类的方法无法满足子类的需求,所以需要重写父类的方法
注解:@Override 建议在重写方法的时候,加上注解 检测是否是满足方法重写。必须满足重写的要求,否则报错
注意:父类中的私有方法,子类无法重写(私有方法不能被继承,所以不能被重写)
代码展示:
public class Father {
public void work(){
System.out.println("父类的方法,一天工作8小时");
}
}
public class Son extends Father{
//如果父类的方法满足不了子类的需要,那么这个时候可以重写父类的方法
//@Override注解 作用:检查是否满足重写的要求
@Override
public void work(){
System.out.println("子类重写的方法,一天工作10个小时");
}
}
5.2方法重写和重载的区别
方法重载vs方法重写
* 位置 方法名 返回值类型 参数列表 访问修饰符
* 方法重载 本类 一致 无关 不一致 无关
* 方法重写 子类 一致 一致 一致 子类要更宽泛
六、super关键字
6.1 super关键字
含义:直接父类的对象
作用:可以调用父类的属性、方法、构造方法
调用父类属性和方法的时候:
1、当子类与父类有重名属性和重名方法的时候,this.属性、this.方法名表示调用子类 的属性和方法
2、当子类与父类有重名属性和重名方法的时候,super.属性、super.方法名表示调用父 类的属性和方法
3、如果没有重名属性和方法,那么this和super表示的都是父类的属性和方法(子类继承 而来)
调用父类的构造方法的时候:
注意:创建子类对象之前,必须要先创建父类的对象
1、super();调用的是父类的无参构造。是可以完全省略的,省不省略都会执行(建议:保 留父类的无参构造)
2、 super调用父类的有参构造,要放到构造方法第一行。super和this不能同时出现
代码展示:
public class Father {
String name="父类的name";
public void show(){
System.out.println("父类中的show方法");
}
}
public class Son extends Father {
String name="子类的name";
public void aa(){
System.out.println(name);//子类继承父类,子类享有父类的属性
System.out.println(this.name);
System.out.println(super.name);
show();
this.show();
super.show();
}
public void show(){
System.out.println("子类的show方法");
}
}
public class Test {
public static void main(String[] args) {
Son son=new Son();
son.aa();
}
}
6.2 子类对象的创建过程
对象的创建过程:
1、开辟空间
2、实例化成员变量
3、执行构造方法
4、将创建的对象赋给对象名
继承后对象的创建过程
先创建其父类的对象,实例化父类的成员变量,执行父类的构造方法,
在创建子类的对象 ,实例化子类的成员变量,执行子类的构造方法
七、多态
7.1程序中的多态
概念:父类引用指向子类对象,从而产生多种形态。
父类引用仅可调用父类所声明的属性和方法,不可调用子类独有的属性和方法。
7.2 多态的特点
a、如果发生多态,那么调用的一定是子类重写的方法。
b、如果发生多态,那么无法调用子类自己独有方法和属性。
编译看左边,运行看右边
7.3 多态的产生条件
a、必须要有继承关系
b、必须要有方法重写
c、必须要有父类的引用指向子类的对象
7.4 向上转型和向下转型
如果发生多态要调用子类自己独有的方法和属性,那么需要发生向下转型。
但是发生向下转型之前必须要发生过向上转型
Pet pet = new Dog(); //向上转型
Dog d = (Dog)pet; //向下转型
7.5 instanceOf关键字
语法: 对象名 instanceof 类型
作用:判断该对象是否属于该类型。属于返回true,否则返回false
应用场景:在向下转型之前,最好先做一个判断。以免发生类型转换异常的错误
Master master=new Master();
//创建Dog对象
Pet pet=new Dog();//向上转型 父类引用指向子类对象
pet.health=50;
master.kanBing(pet);
//如果发生多态,那么无法调用子类独有的方法,如果要想调用子类独有的方法,那么必须要发生向下转型,前提要先发生过向上转型
// dog.swimming();
if(pet instanceof Dog){
Dog dog=(Dog)pet;
dog.swimming();
}
7.6 多态的应用场景
1、方法的参数
2、方法的返回值
//给宠物看病的方法
public void kanBing(Pet pet) { //Pet pet = new Dog();
pet.toHealth();
}
八、abstract
8.1抽象类
应用:abstract修饰类,此类不能new对象。
- 被abstract修饰的类,称为抽象类。
- 抽象类意为不够完整的类、不够具体的类,
- 抽象类对象无法独立存在,即不能new对象。
8.2抽象类的作用
作用:
- 可被子类继承,提供共性属性和方法。
- 可声明为引用,更自然的使用多态
代码展示:
public abstract class Animal {//使用abstract修饰的类称之为抽象类
//每一个动物吃的操作和睡的操作都不一样,所以这两个方法都没必要写出具体的实现
public void eat(){
System.out.println("动物吃");
}
public void sleep(){
System.out.println("动物睡");
}
}
8.3抽象方法
abstract修饰的方法称之为抽象方法
特点:
* 1、抽象方法必须被写在抽象类中
* 2、抽象方法不能有方法体(方法的实现{})
* 3、抽象方法必须在非抽象子类中重写
九、static
static:表示静态的
可以修饰属性、方法、代码块、内部类
9.1静态属性
修饰的属性:静态属性(类属性)
静态变量:通过类名.属性名调用
1、在类的对象之间是共享的
应用场景:在多个对象之间共享变量的时候,应该使用静态变量
代码展示:
public class Student extends Person {
int a; //实例变量
static int b;//类变量
}
//1、创建Student类的对象
Student stu1 = new Student();
Student stu2 = new Student();
stu1.a = 10;
stu2.a = 20;
//实例变量在多个对象之间是独立的
System.out.println(stu1.a); //10
System.out.println(stu2.a); //20
//静态变量在多个对象时间是共享的
stu1.b = 100;
stu2.b = 200;
System.out.println(stu1.b);//200
System.out.println(stu2.b);//200
//静态属性正确的调用方式:类名.属性名调用
Student.b = 300;
9.2静态方法
static修饰方法:静态方法、类方法
静态方法:通过类名.方法名调用
1、静态方法只能调用静态的属性和静态的方法
2、静态方法中不能使用this和super关键字
3、抽象方法不能使用static修饰
4、静态方法不能被重写,但是可以被继承
应用场景:一般在编写的工具类中使用静态方法
代码展示:
public class MyClass {
static int num1=10;//静态变量
int num2=20;//成员变量
public static void aa(){
System.out.println("这是一个静态方法");
// bb();1、静态方法中不能直接调用成员方法 静态方法在类加载的时候就已经存在了,成员方法要等到对象创建才存在
//System.out.println(this.num2);2、静态方法中不能使用this和super关键字
//3、静态方法不能使用abstract修饰 静态方法类加载就已经有了,这个时候就可以被别人使用了,那么抽象方法是一个不完整的方法
//4、静态方法可以被继承,但是不能被重写
//未来写的工具类中的方法都是静态的
}
public void bb(){
aa();
System.out.println("这是一个成员方法");
}
}
9.3 静态代码块
代码块:指的是在程序中出现的一个代码片段,直接使用{}包裹
特点:代码块会在创建对象的时候自动调用,无需手动调用,
代码块会按照先后顺序依次执行,优先于构造方法先执行
static修饰的代码块称之为静态代码块
1、静态代码块在类加载的时候就执行
2、优先于动态代码块
3、只会被执行一次。
代码展示:
public class User {
static int a=10;
//代码块会在创建对象的时候自动调用,无需手动调用
//代码块会按照先后顺序依次执行,优先于构造方法先执行
{
System.out.println("这是代码块1");
}
{
System.out.println("这是代码块2");
}
//静态代码块在类加载的时候自动执行,无需手动调用
//代码块会按照先后顺序依次执行,优先于代码块先执行
//静态代码块只会在类加载的时候执行一次
static{
System.out.println("这是静态代码块");
}
public User(){
System.out.println("这是构造方法");
}
}
9.4 类的加载时机
类加载的时机:
1、创建类对象的时候(new)
2、创建子类对象
3、调用静态属性和方法
4、Class类中提供的静态方法Class.forName()方法的时候(反射)
十、final
10.1 final
final
* 含义:最终的
* 作用:修饰类,修饰方法,修饰属性
10.2、final类
final修饰类:此类不能被继承。
String、Math、System均为final修饰的类,不能被继承。
final修饰方法:此方法不能被覆盖。
意为最终方法,不支持子类以覆盖的形式修改。
10.3、final方法
使用final修饰的方法不能被重写,但是可以被继承
10.4、final变量
final修饰变量:此变量值不能被改变(常量)。
所有final修饰的变量只能赋值一次,值不允许改变。
特点:
* 1、常量必须要赋值
* 常量的最后赋值时机:
* a、非静态常量(没有static修饰的)
* 1)直接赋值
* 2)在代码块中赋值
* 3)在构造方法中赋值(注意:如果一个类有多个构造方法,那么必须要在每一个构造方法中都赋值)
* b、静态常量(使用static修饰的)
* 1)直接赋值
* 2)在静态代码块中赋值
*
* 2、常量不能修改
* 基本类型的常量,值不能修改
* 引用类型的常量,地址不能修改
代码展示:
public class MyClass2 {
//final String name="张三";
// final String name;
// {
// name="李四";
// }
//
//final String name;
//public MyClass2(){
// name="王五";
//}
//static final int a=10;
// static final int a;
// static {
// a=10;
// }
final String a="aa";
static final String b="bb";
String c="cc";
}
public class Test {
public static void main(String[] args) {
// MySonClass mySonClass=new MySonClass();
// mySonClass.play();
// MyClass2.b="bbb";//报错 静态常量不能修改
//MyClass2 myClass2=new MyClass2();
//myClass2.a="aaa";//报错 非静态常量不能修改
//基本类型的常量,值不能修改
final int a=10;
// a=10;//报错,值不能修改
//引用类型的常量,地址不能修改
final MyClass2 myClass2=new MyClass2();
myClass2.c="ccc";
// myClass2=new MyClass2();//地址不能修改
}
}