面向对象
1、类和对象
类:某一类相同事物的抽象描述(公共的属性/行为)
对象 :类中的具体实例(类的对象/类的实例)
**关系:**编程语言中,先有类,根据类创建对象
2、创建类
public class 类名{
//公共的属性 行为
}
3、创建对象
格式:
new 类名();//创建某个类的对象
new:创建对象
注意:
为了更加方便的操作对象,一般会定义变量指向对象
数据类型 变量名 = new 类名();
每个类都是一种数据类型(引用类型)
对象创建好以后,会有类中的属性和行为
4、访问属性和行为
格式
对象.属性//成员变量:类的里面,方法外面定义的变量
对象.行为//成员方法
std.xh//变量
std.eat()//方法
注意:
属性是没有()
行为有()
5、对象的初始化
给对象的属性赋值
对象.属性=值 ;
std.xh = 值;
6、重写toString方法
可以定义查看的内容
封装
1、构造方法
给对象的属性进行初始化
格式:
public 类名(参数列表){
//给类的(对象)属性初始化
}
注意:
-
构造方法没有返回值
-
方法名必须和类名保持一致
-
构造方法写在初始化属性所在的类中
-
构造方法可以有多个
-
构造方法不能手动调用
-
创建对象的时候会自动调用构造方法
-
在创建对象的时候给构造方法的参数进行传参
class Student{
int xh;
String name;
String gender;
int age;
//构造方法:无参构造(不会给属性初始化)
public Student(){
}
//构造方法:给所有属性都进行初始化
public Student(int xh,String name,String gender,int age){//规范:参数名和属性名保持一致
this.xh = xh;//this.xh访问的是成员变量
this.name = name;//this.name
this.gender = gender;//this.gender赋值给gender
this.age = age;//this.age赋值给age
}
}
如果在方法中,出现了同名的局部变量和成员变量,在方法中默认访问的是局部变量,可以通过this关键字访问成员变量
格式:
this.变量
问题:为什么以前不写无参构造,也可以创建?
解答:如果没有手动去写构造方法,JVM会自动创建无参构造
如果手动写构造方法,JVM不会创建无参构造方法
2、封装
封装实体类的属性
实体类:
封装数据的类
工具类:
写工具方法
测试类:
测试代码
封装的格式:
第一步:私有化成员变量(属性)
private 数据类型 变量名;
第二步:成员变量提供公共的set/get方法
public class Book{
private String name;
//set方法:设置属性值
public void setName(String name){//设置
//过滤代码
this.name = name;
}
//get方法:获取值
public void getName(){//获取
return name;
}
}
规范:没有特殊要求,实体类的属性都要进行封装
3、权限修饰符(访问控制符)
控制类中的成员,能否被其它地方访问到
从大到小:
public protected default private
public:公共的,任意位置访问
protected:
default:
private:私有的,只有当前类可以访问
实际案例:超市后台管理系统
Market_Sys
package example2;
import javax.swing.plaf.synth.SynthOptionPaneUI;
import java.util.Scanner;
public class Market_Sys {
//创建Scanner对象
private static Scanner scanner = new Scanner(System.in);
//创建数组,保存会员信息
private static Member[] members = new Member[100];
//定义变量,保存索引值
private static int index = 0;//保存数据的索引值
//显示主页
public static void showMain(){
System.out.println("购物管理系统 > 会员信息管理");
System.out.println("**********************************");
System.out.println("1. 添加会员信息");
System.out.println("2. 修改会员信息");
System.out.println("3. 查询会员信息");
System.out.println("4. 显示所有会员信息");
System.out.println("5. 退出系统");
System.out.println("**********************************");
}
//添加会员信息
public static void addVIP(){
System.out.println("===添加会员信息===");
System.out.println("请输入会员卡号:");
//录入会员卡号
String num = scanner.next();
System.out.println("请输入会员生日(月/日<用两位数表示>):");
//录入生日
String birthday = scanner.next();
System.out.println("请输入积分:");
//录入积分
String score = scanner.next();
//录入会员信息,保存起来 :实体类+数组
//创建Memeber对象
Member member = new Member();
//把录入的数据保存到member对象中
member.setNum(num);
member.setBirthday(birthday);
member.setScore(Integer.parseInt(score));
//把会员保存到数组中
members[index] = member;
index ++;
System.out.println("添加会员信息成功!");
}
//修改会员
public static void updateVIP(){
System.out.println("===修改会员信息===");
System.out.println("请输入会员卡号:");
//录入输入的卡号
String num = scanner.next();
System.out.println("*********************************");
System.out.println("1 修改会员生日");
System.out.println("2 修改会员积分");
System.out.println("*********************************");
//录入选择
String option = scanner.next();
switch (option){
case "1":
//修改生日
update(num,1);
break;
case "2":
//修改会员积分
update(num,2);
break;
default:
System.out.println("选择有无!");
break;
}
System.out.println();
}
//方法:修改用户信息
//num:卡号(要修改哪个用户) option:修改内容 1:修改生日/2:修改积分
public static void update(String num,int option){
//遍历所有会员
for (int i = 0; i < index; i++) {
//当前会员: members[i]
Member member = members[i];
//判断当前会员是不是用户指定要修改的会员
if(member.getNum().equals(num)){
//判断修改什么内容
if(option==1){
//修改生日
System.out.println("请输入修改后的生日:");
//录入新的生日
String newBirthday = scanner.next();
//修改当前会员生日
member.setBirthday(newBirthday);
System.out.println("生日修改成功");
}else if(option==2){
//修改积分
System.out.println("请输入修改后的积分:");
//录入新的积分
String newScore = scanner.next();
//修改当前会员积分
member.setScore(Integer.parseInt(newScore));
System.out.println("积分修改成功");
}
return ;//结束函数,不需要再继续循环判断
}
}
//卡号不存在
System.out.println("卡号不存在");
}
//查询会员
public static void findVIP(){
System.out.println("===查询会员信息===");
System.out.println("请输入会员卡号:");
//录入会员卡号
String num = scanner.next();//用户想要查询的卡号
//根据卡号,从members找会员信息
//遍历数组:根据索引值index遍历(假设数组只保存了5个数据,有必有遍历100个数据?)
boolean flag = false;//假设没有
for (int i = 0; i < index; i++) {
//当前member对象
Member member = members[i];
//判断当前这个member对象是我们要的对象吗?
//根据卡号判断
if(member.getNum().equals(num)){//当前会员卡号 和 录入的卡号比较 ==:基本类型/引用类型 String:引用类型
//如果相同,代表找到了
flag = true;
//显示头信息
System.out.println("会员号\t生日\t积分");
System.out.println(member.getNum()+"\t"+member.getBirthday()+"\t"+member.getScore());
break;
}
}
if(flag==false){
//没找到
System.out.println("会员号不存在!");
}
System.out.println();
}
//显示所有会员
public static void findAllVIP(){
System.out.println("===显示所有会员===");
if(index==0){
System.out.println("没有任何数据!");
}else{
//显示头信息
System.out.println("会员号\t生日\t积分");
for (int i = 0; i < index; i++) {
Member member = members[i];
System.out.println(member.getNum()+"\t"+member.getBirthday()+"\t"+member.getScore());
}
}
System.out.println();
}
//程序主入口
public static void main(String[] args) {//主函数有static,在主函数中去访问其它成员,其它成员必须有static
while(true){
//显示主页
showMain();
//获取用户的选项(键盘录入的数据):Scanner对象
//提示信息:
System.out.println("请输入数字(1-4):");
//调用方法获取录入的数据
String option = scanner.next();//返回的字符串
// System.out.println("录入的数据是:"+option);
//判断用户录入的内容
switch (option){
case "1":
//添加会员信息
addVIP();
break;
case "2":
//修改会员信息
updateVIP();
break;
case "3":
//查询会员信息
findVIP();
break;
case "4":
//显示所有会员信息
findAllVIP();
break;
case "5":
//显示所有会员信息
System.exit(0);//结束程序
break;
default:
System.out.println("选项有误,请重新选择:");
break;
}
}
}
}
Member
package example2;
//封装会员信息
public class Member {
private String num;//卡号
private String birthday;//生日
private int score;//积分
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Member{" +
"num='" + num + '\'' +
", birthday='" + birthday + '\'' +
", score=" + score +
'}';
}
}
继承
1、static关键字
static:静态
用在属性上:
静态成员变量,在内存中只有一份,是共享数据
访问方式:
类名.静态属性
对象.静态属性(不推荐使用)
常量:
public static final int NUM = 123;
静态方法:
一般用在工具类中
public static void main(String[] args)
访问方式:
对象.方法名()
类名.方法名()(推荐使用)
注意:
静态方法只能访问静态成员
代码块
静态代码块
static{
}
特点:静态代码块的内容只会在加载类的时候执行一次
对比非静态代码块:
{}
特点:每次创建对象都会执行一次
2、继承
继承:
类与类之间的一种关系
关键字:
extends
格式
public class 类名1 extends 类名2{
}
//类名1:子类
//类名2:父类
单继承:
子类只能有一个直接父类
特点:
子类继承父类后,可以去使用父类的属性和行为
注意:
父类私有成员的不能继承
父类的构造方法不能继承,但是可以在子类中调用父类的构造方法(子类会默认调用父类的无参构造方法)
3、super关键字
父类空间引用
1、调用父类的构造方法:给父类构造方法初始化
super(实参列表);//调用父类无参构造
super(name ,color,weight);//调用父类3个参数的构造函数
注意
super调用构造方法时,只能位于第一个语句
2、获取父类的属性
super.属性名;
问题:父类中的toString()方法,不能满足子类的需求
4、方法的重写
使用:
父类方法无法满足子类需求,可以在子类中重写该方法
格式:
方法名和参数列表一致
前提:
一定要有继承(或实现)关系
对比方法的重载:
方法名相同,参数列表不同
在同一个类中,不需要继承关系
5、final关键字
final:最终的
1、修饰类
类不能被继承
2、修饰方法
方法不能被重写
3、修饰属性(变量)
变量不能重新赋值
4、常量
public static final int NUMBER = 1;
注意:常量全部大写
6、包的概念
文件夹
不同包中的内容如何访问:
导包
package //声明包,指定当前文件所在包
package test1;//当前类在test1包中
package test2;//当前类在test2包中
import //包名.类名;
import test1;//把test1包导入
import test1.person;//把test1包中的person类导入
import test1.*;//把test1包中的全部类导入
//*通配符,所有内容
注意:
包名全部小写
同包中的内容如何访问:
7、Object类
Object类是所有类的父类
常用方法
1、equals()方法
比较内存地址
注意:如果子类没有重写equals()方法,默认都是比较内存地址
思考:在比较字符串(String)时,为什么可以直接用equals()比较字符串内容?
原因:
String重写了equals()方法,在String的equals()方法中比较的是字符串内容
2、toString()方法
获取对象的字符串(以字符串的形式表示对象)
实体类中一般会重写toString方法
3、hashCode()方法
获取对象的哈希值(以数字的形式表示对象)
4、getClass()方法
获取运行时的一个类
注意:所有的子类如果没有去重写equals()方法,默认都比较内存地址,如果子类想要修改比较规整,就要重写equals()方法
抽象与接口
1、抽象
关键字:
abstract
抽象类:用abstract修饰的类
public abstract class 类名{}
抽象方法:用abstract修饰的方法
修饰符 abstract 返回值类型 方法名();
注意:
- 抽象方法没有方法体
- 一个类中如果有抽象方法体,这个类必须是抽象类
- static和abstract不能一起用:static修饰方法后,方法可以通过类名访问
- 抽象方法不能调用
- 如果父类中有抽象方法,子类一定要重写
- 抽象类中可以有抽象方法,也可以没有
- 抽象类不能创建对象
- 抽象类就是给子类继承用的
作用:要求子类强制重写
2、接口
更加彻底的抽象,接口中都是抽象方法(定义规范)
作用:
解耦,降低代码耦合性
接口关键字
interface
格式
public interface 接口名{
//抽象方法
}
注意:
接口不能创建对象
使用接口:
创建接口实现类
实现:
类与接口之间的关系
对比继承:
继承(类于类之间)
实现关键字:
implements
public class 类名 implements 接口名{
}
注意:
- 一个类实现了接口,就要实现(重写)接口中的抽象方法
- 接口中的修饰符可以不写,默认是public,可以省略
- 一个类实现接口的同时可以继承另外一个类。(先继承再实现)
public class 类名 extends 父类 implements 接口1,implements 接口2{
}
- 一个接口可以有多个实现类
接口与接口之间的关系:继承
注意:接口之间的继承是多继承,类于类之间是单继承
Day14多态
简单理解: 一个对象可以有多个形态
例如:父类:Animal
子类:Cat Dog Pig
定义父类型变量Animal a;//变量a可能是Cat/Dog/Pig
注意:多态只有在运行的时候才能知道具体是谁
多态的体现:
父类的引用类型变量执行子类对象
接口的引用类型变量指向接口实现类对象
例如:
Animal cat = new Cat();
//Animal cat:父类的变量
//new Cat():创建子类对象
1、父类型变量指向子类对象
多态的使用前提:
必须存在继承或者实现关系
注意:
-
在多态情况下,访问的是父类成员,不能访问子类特有成员
-
在多态情况下,如果子类和父类存在同名的属性,访问的是父类属性
-
在多态情况下,如果子类和父类存在同名的非静态方法,访问的是子类方法
-
在多态情况下,如果子类和父类存在同名的静态方法,访问的是父类方法
使用:
用在参数列表中,可以接收更多类型的参数(所有子类型数据)
如何判断多态的具体类型:
instanceof关键字
对象 instanceof 类名
//判断对象是否属于某个类型
//测试类
public static void showMsg(Animal aniaml){
if(animal instanceof Cat){
Cat cat = (Cat)animal;
System.out.println(cat.age);
System.out.println("我是cat,我爱老鼠");
}else if(animal instanceof Dog){
Dog dog = (Dog)animal;
System.out.println("我是Dog,我爱猫咪");
}else if(animal instanceof Pig){
Pig pig = (Pig)animal;
System.out.println("我是pig,我爱睡觉");
}
}
//实体类Animal
public String name;
public String color;
//实体类Cat
public String age;
概念:
向上转型(自动):
Animal cat = new Cat();
向下转型(强制转换):
一般先使用instanceof进行判断
Cat cat = (Cat)animal;
2、接口类型变量指向接口实现类对象
接口的引用类型变量指向接口实现类对象
//没有使用多态
StudentDaoImple studentDao = new StudentDaoImple
//使用多态
StudentDao studnetDao1 = new StudentDaoImpl();
//StudentDao studentDao1 :接口类型的变量
//new StudentDaoImpl():接口实现类对象
好处:
解耦,提高代码的扩展性和可维护性
分层思想(三层架构)
表现层:
用户打交道
业务层
具体实现业务逻辑功能
持久层
数据的持久化
项目中如何体现思想:
分层:创建不同的包
表现层:controller包
业务层:service包
持久层:dao包
3、内部类
匿名内部类
没有名字的类
作用:
给接口创建接口实现类
给抽象类创建子类
创建对象(抽象类/接口)
格式:
new 接口(){
//实现接口中的抽象方法
};
使用:
如果接口实现类对象,只使用一次,那就可以直接使用匿名内部类进行创建。
一般在传参的时候使用(调用的方法需要一个接口类型的参数,可以直接使用匿名内部类进行传参)