面向对象
面向对象是一种思想
面向过程 注重的是“步骤”
面向对象 注重的是“对象”
对象
对象:具有明确的属性和行为(功能)的实体
类
猫类、狗类、人类
类:是一组具有相同属性和行为的对象的集合
属性 行为
人 姓名、性别、年龄、身高 唱歌、跳、rap、打篮球
车 颜色、品牌、价格、轮子个数 载人、加速、减速....
猫 年龄、性别、姓名、品种、颜色 喵喵、找老鼠、上树......
类有两个组成部分:
1、属性 -------> 成员变量
2、行为 -------> 成员方法
类和对象的关系
1、对象是具体的,类是抽象的
2、面向对象就是 从具体到抽象,从抽象到具体的过程
如何创建类
1、确定类名
2、成员变量
3、成员方法
Student类
public class Student {
//属性=====成员变量 (写在类的里面,方法的外面的变量)
String name; //姓名
int age;//年龄
double height;//身高
char sex ;//性别
String address;//住址
//行为=====成员方法
public void study() {
System.out.println(name+"学习~~~~~~~~~~~");
}
public void sleep() {
System.out.println("睡觉~~~~~~~~~~");
}
}
如何创建对象
1、创建对象
类名 变量名(对象名) = new 类名();
2、通过对象去调用类的属性
对象名.属性名
3、通过对象去调用类的方法
对象名.方法名()
要想调用一个类的方法和属性,必须要先要创建这个类的对象
测试类
public class Test {
public static void main(String[] args) {
//创建Student对象 类名 变量名(对象名) = new 类名();
Student stu = new Student();
//调用对象的属性(成员变量) 存值
//属性的功能 存值 取值
stu.name = "cxk";
stu.age = 30;
stu.sex = '男';
stu.height = 180;
stu.address = "武汉";
//调用对象的属性 取值
System.out.println("姓名为:"+stu.name);
System.out.println("年龄为:"+stu.age);
//调用对象的方法 对象名.方法名();
stu.study();
}
}
成员变量和局部变量
区别:
1、定义的变量位置不同
a、定义在类中,方法外的变量称之为成员变量
b、定义在方法中的变量称之为局部变量
2、作用域不相同(本类)
a、成员变量,在整个类中都能被访问
b、局部变量,只能在变量所在大{}中被使用
3、初始值(默认值)不同
a、成员变量,系统会赋予默认值
b、局部变量,没有默认值(所以要注意:局部变量必须要赋值才能使用)
4、重名问题
a、成员变量不能重名
b、局部变量可以在不同的作用域中定义重名变量
5、就近原则
当成员变量和局部变量名相同的时候,使用的时候采用就近原则
6、生命周期不同
a、成员变量 是随着对象在堆内存中,对象被销毁,成员变量被销毁
b、局部变量 因为局部变量在栈内存中,当方法执行完成之后,就会被销毁
测试
1、设计个图形类,设计两个方法,一个求周长(返回周长),一个球面积(返回面积)
- 代码实现
public class Rectangle {
//成员变量
double length;
double width;
//成员方法
public double area() {
return length *width;
}
public double perimeter() {
return (length + width )*2;
}
}
public class Test {
public static void main(String[] args) {
//1、创建Rectangle对象
Rectangle r = new Rectangle();
//2、给对象的属性赋值 (调用对象的属性)
r.length = 30;
r.width = 20;
//3、求面积和周长 (调用对象的方法)
double mj = r.area();
System.out.println("面积为"+mj);
double zc = r.perimeter();
System.out.println("周长为"+zc);
}
}
面向对象编程(OOP)
封装、继承、多态
封装
面向对象中的封装
隐藏类的实现细节,对外提供公共的方法。
1、私有化属性
2、对外提供公共的方法 setter/getter
private 私有的 只能在本类中使用
代码演示
public class Dog {
private String name;
private int age;
private char sex;
//alt + shift + s ------- > getters/setters
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;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
this关键字
this关键字的含义是:当前类的对象
this关键字的用法
调用属性
this.属性名
调用方法
this.方法()
调用构造方法(使用的很少)
this();
this(构造参数。。。。);
注意:调用类的构造方法,要方法第一行代码
当如果没有变量名冲突的时候,this关键字是可以省略的。
构造方法
构造方法就是创建对象的方法
构造方法
语法:
访问修饰符 方法名(){
}
访问修饰符:public
方法名:必须与类名一致(区分大小写)
() :构造参数列表
如果一个类没有定义构造方法,那么系统会默认给这个类提供一个无参构造方法
如果这个类定义了构造方法,那么系统不再提供无参构造
继承
为什么要继承
为了解决代码的重用性
如何继承
1、编写父类
2、编写子类
3、让子类继承自父类
继承的语法:
public class 子类 extends 父类{
}
继承之后特点(好处)
1、子类继承父类,那么子类可以享有父类的非私有属性和方法
2、子类也可以有自己独有的属性和方法
3、在java中只支持单继承(一个父类可以有多个子类,但是一个子类只能有一个父类),可以多层继承
4、在java中最顶端的类叫做 Object类, 在java中如果一个类没有继承任何的父类,那么默认继承自Object类
父类和子类之间的关系
在程序中
被继承的类 称之为 父类、超类、基类
继承类 称之为 子类、派生类
子类 is a 父类
子类的创建过程
子类在创建对象的时候,会先去创建父类的对象
如果在父类中加入一个有参构造,那么子类就会报错
原因:因为父类中有了有参构造,那么系统不会去提供无参构造,子类在创建的是,默认又去调用了父类的无参构造
创建对象的同时对属性进行赋值
在子类中创建有参的构造方法
public Student(String name,int age) {
//调用父类的构造方法
super(name,age);
}
在父类中创建有参构造
public Person(String name,int age) {
this.name = name;
this.age = age;
}
super关键字
super 表示直接父类对象
super 关键字的作用
调用父类的属性、方法、构造方法
调用父类的属性:super.属性名
如果字类中没有这个属性,那么调用的是父类的属性
那么使用this.属性名、super.属性名,表示都是一样的
调用父类方法: super.方法名
如果子类中没有这个方法,那么调用的是父类的方法
如果子类中有相同的名字的方法(方法的重写)
调用父类的构造方法: super(构造方法)
必须要写在构造方法的第一行代码
方法重写
在子类中出现与父类有相同签名的方法,就叫做方法的重写
重写的要求:
重写的方法 方法名、返回值类型、参数列表要一致,访问修饰符要比父类的大
父类Person中work方法
public void work() {
System.out.println("这是父类的work方法");
}
在子类中重写父类的work方法
@Override
public void work() {
//super.work();
System.out.println("喝水");
System.out.println("抽根烟");
System.out.println("工作");
System.out.println("看看时间");
System.out.println("下班");
}
@Override 注解 检测这个方法是否方法重写
方法重写与方法重载的区别
类型 | 位置 | 方法名 | 返回值 | 参数列表 | 访问修饰符 |
---|---|---|---|---|---|
方法重写 | 子类 | 相同 | 相同 | 相同 | 比父类大 |
方法重载 | 本类 | 相同 | 无关 | 不同 | 无关 |
访问修饰符
类型 | 本类 | 本包 | 不同包子类 | 所有 |
---|---|---|---|---|
private | √ | |||
默认的 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
static关键字
static 静态的
修饰符: 属性、方法、代码块、内部类
static修饰的属性: 静态变量
1、静态变量直接通过类名.变量名调用,不需要创建类的对象
2、静态变量也可以通过对象来调用,是因为它在堆内存中有一份拷贝
3、静态变量在对象之间是共享
在开发中,静态的变量用的很少。但是静态常量用的多
public static final 类型 常量名 = 值:
常量:
常量不能改变
常量必须要赋值
static修饰的方法: 静态方法
1、静态方法直接通过类名.方法名调用,不需要创建类的对象
2、静态方法也可以通过对象来调用,是因为它在堆内存中有一份拷贝
3、静态方法只能访问静态的变量和静态方法
4、静态方法中不能使用this和super关键字
注意:非静态方法可以调用静态方法
static修饰的代码块 静态代码块
1、当类被加载的时候,静态代码块就会被执行
2、静态代码块只会被加载一次
3、静态代码块,优先于类的所有信息先执行
final关键字
final关键字
修饰属性 常量
1、常量一旦定义不能修改
2、必须要赋值
如:public static final String USERNAME= "root";
修饰方法
1、final修饰的方法不能被重写
修饰类
1、final修饰的类不能被继承
注意: 静态方法不能被重写
多态
生活中的多态:同一个事物在不同环境下有不同的状态
人在不同的环境下身份不同
f1键在不同的软件下作用不同
程序中的多态:同一个对象在不同的环境下调用,功能不同
多态产生的条件
1、必须要有继承
2、父类的引用指向子类的对象(向上转型)
3、一定要有方法的重写
多态的特点
1、如果发生了多态,那么调用方法一定是子类重写的那个方法
2、如果发生了多态,那么父类引用无法调用子类自己的方法
如果想要调用,那么就必须发生 向下转型
在发生向下转型之前,必须要发生向上转型。否则会有异常java.lang.ClassCastException(类转换异常)
3、如何避免程序出现类转换异常
在转换之前,先判断是都是这个类型
//判断对象是否是某一个类型
//判断animal是否是Dog类型
if(animal instanceof Dog) {
Dog d = (Dog)animal;
d.show();
}
4、编译看左边, 运行看右边
抽象类
用abstract关键字修饰的类就称之为抽象类
抽象类的特点: abstract关键字修饰
1、有抽象方法的类必须是抽象类
2、抽象类也可以没有抽象方法(没什么意义)
3、抽象类不能被实例化
抽象类的作用 当爹的 一般都是用来作为父类被使用
抽象方法的特点: abstract关键字修饰
1、抽象方法不能有方法体(不同有{})
2、抽象方法必须被子类重写,除非自己也是一个抽象类
接口
生活中的接口:接口定义了规范,是一种约束
public class 类名{
成员变量
成员方法
}
如何定义接口:
public interface 接口名{
}
接口中只能包含:
静态常量 默认加上了 public static final修饰
抽象方法 默认加上了 public abstract修饰
如何实现接口
public class 实现类 implements 接口名{
//重写接口的抽象方法
}
如果使用接口 (利用多态)
MyInterface mi = new MyInterfaceImpl();
mi.show();
接口的特点:
1、一个类可以实现多个接口 (类与接口之间是实现关系)
2、一个接口可以继承多个接口(接口与接口之间是继承关系)
3、一个类只能继承一个类
接口其实使用特殊的抽象类
接口和抽象类的区别
1、接口中必须都是抽象方法,抽象中类可以没有
2、接口中必须是静态常量,抽象类都可以
3、接口是被类实现(implements),抽象类是被继承(extends)
4、都不能被实例化
图书管理系统
- 接口类
public interface UserInterface {
//用户登录
boolean login(User user);
//用户注册
void register(User user);
}
- 接口实现类
public class UserInterfaceImpl implements UserInterface {
//保存所有的用户信息
User[] users = new User[0];
@Override
public boolean login(User user) {
//遍历User数组中的所有用户对象
for (int i = 0; i < users.length; i++) {
User u = users[i];
if(user.getUsername().equals(u.getUsername()) && user.getPassword().equals(u.getPassword())) {
return true;
}
}
return false;
}
@Override
public void register(User user) {
//定义长度比以前数组大1的新数组
User[] users_1 = new User[users.length+1];
for (int i = 0; i < users.length; i++) {
users_1[i] = users[i];
}
//将传进来的User存在数组的最后一个位置
users_1[users_1.length-1] = user;
//将新数组赋给,成员变量的数组
users = users_1;
}
}
- User实体类
public class User {
private String username;
private String password;
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public User() {
super();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- 菜单类
public class Menu {
public static final int REG = 1;
public static final int LOG = 2;
public static final int EXIT = 3;
//定义UserInterfaceImpl 对象,调用登录和注册的方法
UserInterface userInterface = new UserInterfaceImpl();
Scanner sc = new Scanner(System.in);
public void menu() {
System.out.println("欢迎光临XXXX系统");
System.out.println("1、注册");
System.out.println("2、登录");
System.out.println("3、退出");
int num = sc.nextInt();
switch (num) {
case Menu.REG:
System.out.println("请输入注册用户名");
String username = sc.next();
System.out.println("请输入注册密码");
String password = sc.next();
User user = new User(username, password);
userInterface.register(user);
menu();
break;
case Menu.LOG:
System.out.println("欢迎登录");
System.out.println("请输入用户名");
String username1 = sc.next();
System.out.println("请输入密码");
String password1 = sc.next();
User user1 = new User(username1, password1);
boolean b = userInterface.login(user1);
if(b == true) {
System.out.println("进入图书管理系统~~~~");
}else {
System.out.println("登录失败,请检查你的账号和密码");
}
menu();
break;
case Menu.EXIT:
System.out.println("欢迎下次使用~~~~");
break;
default:
System.out.println("您的选择有误~请重新输入");
menu();
break;
}
}
}
- 测试
public class Test {
public static void main(String[] args) {
Menu menu = new Menu();
menu.menu();
}
}