面向对象
定义
类:【具备相同属性和方法的一类对象的集合】就是描述对象属性和方法的一个模板
对象:真实存在的实体
//思考过程 先有对象 抽象出类
//先写类 再创建对象 使用
关系
类是对象的抽象化 对象是类的实例化
实体类:new成对象是真实存在的实体
测试类 主类 :main()所在类
Scanner Random 工具类 功能类:存放管理一类方法
对象拥有所属类里所有公开的属性和方法
类的组成:
属性:以声明变量的形式 描述对象所具备的特性 一般不需要赋真实值
方法:以编写方法的形式 描述整个类所有对象 所具备的功能
练习
批量循环录入保管3个学生
每个学生都有 String ID(不重复) String name int age char gender double score 属性
保存完毕后 使用增强for循环 展示这三名学生信息
利用增强for循环 展示用户输入性别的信息
利用增强for循环 将不及格的成绩统一+10分
//创建Student实体类
public class Student{
String ID;
String name;
int age;
char gender;
double score;
//设计方法
public String toString(){
//syso("中国你好");
return "ID:"+this.ID
}
}
Student s1 = new Student();
syso(s1.toString());
//测试类中
//创建Student类型的数组 用于批量保存学生对象
Student[] ss = new Student[2];
//通过循环 批量保存
for(int i =0;i<ss.length;i++){
//要给数组的每一个房间 创建一个学生对象
ss[i] = new Student();
syso("请输入xxx");
ss[i].ID= input.next();
ss[i].name = input.next();
ss[i].age = input.nextInt();
ss[i].gender = input.next().charAt();
ss[i].score = input.nextDouble();
}
//int[] nums = new int[3];
//nums[0] = 100;
//for(int n : nums){
// n=1000;
//}
//syso(nums[0]);//100
for(int i =0;i<nums.length;i++){
nums[i] = input.nextInt();
}
String name = "";
String name = new String("");
//使用增强for循环展示所有元素
for(Student s : ss){
if(s!=null){
syso(s.ID+"\t"+s.name+"\t"+s.age+"\t"+s.gender+"\t"+s.score);
}
}
练习:
声明Dog类 描述狗的 昵称 年龄 品种(brand) 没有初始值
有一个show() 展示狗的信息
编写测试类 创建合适数组 循环录入三只狗的信息 遍历调用每只狗的show()
方法
定义:
将完成一定功能的代码 进行打包【封装】
方法不能互相嵌套 只能调用 但是要防止循环调用
本类方法调用本类其他资源 可以使用this.也可以省略this. this本类将来的对象
跨类方法调用资源 则需要创建对象调用 (如果调用的是静态资源 还可以使用类名直接调用)
Arrays.sort()
Math.PI 静态常量
四要素:
1.方法名和功能 结合记忆
2.方法所属的类型 nextInt()
3.方法的参数 char c = charAt(int)
4.方法的返回值 int num = input.nextInt();
input.nextInt()==1?'男':'女';
Arrays.toString(数组名);
String str = Arrays.toString(数组名);
sout(str);
syso(input.nextInt())
int n = input.nextInt()+10
if("".equals("")){
}
char c = input.next().charAt(0);
input.nextInt()
syso(Arrays.toString(nums));
Arrays.sort(nums);
方法编写
public class Test{
public static int num; //0
public static void main(String[] args){
//方法体 实现功能
public static int age;//报错 不能添加访问修饰符 也不能添加静态
syso(age);//局部变量 没有赋值使用则报错
syso(num);//0
}
}
访问修饰符
只用于修饰全局变量 或方法(局部资源不能使用访问修饰符)
public公共的公开的跨类 跨包
//protected受保护的跨类 半可跨包不可跨包 为继承设计
什么都不写默认的 跨类 不可跨包
private私有的 不能跨类 不能跨包
static 静态的
会影响修饰的代码的加载时机所在的类被使用 则static修饰的资源 立即加载 且只加载一次
静态资源的加载:只要一碰这个类的任意资源 立即加载 可以通过对象调用 还可以通过类名直接调用
Param.静态资源
Param p = new Param();
p.静态资源
非静态资源的加载:只有通过创建该类的对象 才能加载只能通过对象调用
Param p = new Param();
p.非静态资源
静态代码块
类下直接编写
static{
静态代码块 //静态代码块中的代码 只要加载就会执行
//只能调用到在他之前声明的静态属性
}
静态属性
1.可以继续使用对象调用
2.可以直接使用类名调用存储于 方法区中的 元数据区中
3.所有对象及类名共用这个属性
静态方法
1.可以继续使用对象调用
2.可以直接使用类名调用
3.静态方法中 不能使用this关键字
调用原则
因为静态资源优先加载 所以不能调用任何非静态资源(非静态资源 在new对象时才加载)
非静态资源 可以调用静态资源
//使用类时 第一时间加载所有静态资源 且只加载一次 ==》普通资源 在new对象时加载
//0.静态代码块 加载同时执行 ===》静态方法虽然已经加载 但需要调用才执行
//静态代码块 只能调用到在他之前声明的静态属性
//1.静态资源 不能调用非静态资源 ==》非静态资源可以调用静态资源
//2.静态资源可以通过类名直接调用 也可以继续使用对象调用 Math.PI Arrays.sort()
//3.静态属性 所有对象共享 ==》存储在方法区的元数据区中
//4.静态方法 静态代码块 内部不能使用this ==》因为静态方法有可能使用类名直接调用 没有对象
/*
* static 修饰属性
* 1.依然可以使用对象调用 增加了使用类名调用
* 2.静态属性 所有对象 以及类名共用 存储在方法区中的元数据区内
*
* static 修饰方法
* 1.依然可以使用对象调用 增加了使用类名调用
* 2.静态方法中 不可以使用this
*
* static 修饰代码块
* 1.加载就执行 不受调用
* 2.内部不能使用this
* 3.只能调用在其前面声明的静态属性
*
* 静态资源 不能调用非静态资源==》非静态资源可以调用静态资源
* 静态资源加载 从上向下
*/
使用场景
属性:如果确实需要所有对象共享这个全局变量 可以添加static
注意:一般在main()所在的类中编写其他方法 或者全局变量 建议添加static
其他类中 分析考虑是否添加 一般不加
Arrays
Math.
练习
class User
static int i=0;
int id
String name
class Test
User[] us = new User[2];
案例
定义一个等级规则 class Levelint level, int money, double decont,double score
等级累计金额折扣积分
1 00.980.001Level l1 = new Level(); l1.等级 l1.金额
2 10000.950.005
3 40000.9 0.01
4 80000.85 0.05
5 130000.78 0.08
6 200000.75 0.1
Userint level=1int score=0double money=200000 double allMoney=0
输入消费金额 然后 计算折扣后 实际消费金额 更新用户信息
返回值
不带返回值方法
编写:在方法名前 void
调用:直接调用方法即可
例如:Arrays.sort(数组名);
带返回值方法
int length()
char charAt(int)
注意:一个方法最多只有一个返回值
编写:确认方法返回值类型 用该类型 替换void
方法最后一定要通过return关键字 返回同类型的值 要保证每种情况 都有返回值
调用:1.声明一个同类型的变量 接收这个方法 2.可以直接输出这个方法 3.根据返回值的特性直接参与运算
调用带返回值的方法 就是在调用这个值
使用场景:如果一个方法运算后的结果 在后续业务中需要反复使用 建议该方法做成带返回值的方法
return:1.结束该方法 2.在带返回值的方法中 借助return返回一个符合要求的值
案例
class User String name int age
创建Util工具类
1.添加用户 返回数组询问用户 人数 进行添加用户对象 返回这些用户对象
测试类中 调用该方法 获得数组 展示数组中的元素
public class Pet{
String petName;
int petAge;
}
public class Student{
String name;
int age;
Pet pet;
}
public class Impl{
public Student getStu(){
Student s = new Student();
return s;
//return new Student();
}
public Pet getPet(){
int i = 10;
if(i==10){
return new Pet();
}
//return null;//兜底 让虚拟机认为每种情况都有返回值 其实这里执行不到
}
}
//测试类中
Student s0 = new Student();
s0.name = new String("张三");
s0.age = 18;
s0.pet = new Pet();
s0.pet.petName = "豆豆";
s0.pet.petAge = 1;
Student[] ss = new Student[3];
ss[0] = new Student();
ss[0].name = "李四";
ss[0].age = 20;
ss[0].pet = new Pet();
ss[0].pet.petName = "花花";
ss[0].pet.petAge = 2;
=============================================
Pet[] pp = new Pet[3];
pp[0] = new Pet("aa",1);
pp[1] = new Pet("",2);
pp[2] = new Pet("",1);
ss[0].pet = pp[0];
public int[] getNums(){
int[] n = new int[]{1,3,4};
return n;
}
public int getNum(){
int i = 5;
if(i==5){
return 3;
}else if(i!=5){
return 7;//虽然这个else不会执行 但是必须保证方法的任何情况都有返回值
}
return 0;
}
public boolean getBool(){
return true;
}
//接收带返回值的方法
//方法 调用一次 就会执行一次
int l = xx.getNum();
syso(xx.getNum());
int n = xx.getNum()+5;
if(xx.getBool()){
}
int sel = input.nextInt();
if(sel==1){
}else if(sel==2){
}else{
}
syso(Arrays.toString(数组名));
练习
创建Util类 已有一个User[] us 存好了几个元素编写一个方法 User getUser() 用于查询某个姓名的用户是否存在 存在则返回这个用户对象 否则返回null
(先创建一个User类 String name int age 再Util类中创建一个3个长度的静态数组 使用静态代码块存放三个用户对象)
创建一个class Impl类
其中有一个方法 int[] show()
功能:先通过循环 随机给一个长度为8的int类型的数组nums 赋值 值的范围是55-65
返回其中所有的偶数 数组
创建测试类class Test
调用show() 展示数组
参数
参数:会影响方法运算结果的变量 可以有多个
编写:以声明变量的形式 将参数放入方法后的小括号中 如果有多个参数 以,隔开
接下来 【将参数当成已知量 直接参与方法体的编写】
调用:1.观察原始方法的参数列表数量 类型 顺序 含义
2.根据形参参数列表 准备对应的真实值(实参)
3.将实参一一对应 传入方法
使用场景:如果编写方法所需的变量 暂时无法获取 可以使用形参来占位编码
1.形参属于局部变量 但是没有值 直接参与编写方法体
2.如果传递的是引用数据类型 则传递的是地址 导致 实参与形参共享空间
3.实参要与形参一一对应的传递 尤其注意含义
同一个代码块中 使用变量名来区分变量===》声明的变量名相同 就是相同变量 会报错
而方法的区分 1.方法名不同 肯定是不同方法 2.形参参数列表
public class Impl{
public void getNums(int num){//编写方法时 创建形参
int[] nums = new int[num]; //将形参 当成已知量 编写方法体
}
}
//测试类中
Impl impl = new Impl();
syso("请输入数组长度");
int n = input.nextInt();
impl.getNums(n); //调用带参方法时 将准备好的数据(实参)一一对应传入
练习
先创建一个Impl类 implement
内部有一个带参带返的方法 jiSuan
参数为 两个整数 和一个字符(+ - * /)
方法体 判断字符要做什么运算 返回如下效果
5 + 8 = 13
7 * 3 = 21
除法时 注意判断除数是否为0
练习
class Impl
int[] getNums(int num)
参数表示用户输入的数组长度通过循环 给数组随机赋值 10-20 返回这个数组
boolean showNums(int[] nn,int num)
接收一个数组和要查询的数字作为实参 通过二分查找法 方法负责返回这个数字是否在数组中
class Test
先调用getNums() 得到返回值 作为showNums()的实参
创建一个User类 String name int age String toString()
创建一个Impl类创建一个普通用户数组 长度为4
编写方法 User[] addUser()该方法负责循环向数组赋值 最终返回这个数组
编写方法 User getUserByName(String name,User[] us)该方法接收第一个方法返回的数组和要查询的姓名 返回用户对象或者null
编写方法booleanchangeMessage(User u,int age) 该方法接收第二个方法返回的对象 进行年龄修改 年龄只能是18-30岁 否则返回false
创建测试类根据逻辑 调用三个方法
创建一个Dog类 String brand品种int age
创建Util类
编写方法 Dog addDog(String b,int a)传入品种和年龄 返回这个对象
编写方法 Dog[] addDogs(int num)传入狗的数量 创建一个Dog类数组
循环调用第一个方法 得到Dog对象 存入数组 最后返回这个数组
编写方法intgetNumByAge(Dog[] ds,String b)传入狗数组和一个品种 返回改品种狗的数量
编写方法DoggetMixAge(Dog[] ds)传入狗数组 返回其中年龄最小的那只狗
编写方法intgetAvgAge(Dog[] ds) 传入狗数组 返回平均年龄
创建测试类 测试以上方法
Random r = new Random();
r.nextInt();
r.nextInt(int num)
方法的重载
1.在同一个类中
2.方法名相同
3.参数列表不同数量 类型 顺序 含义
Scanner nextInt()
Random nextInt(int)
nextInt()
public void getFruit(int l,String name,int i){
syso("总共"+l+"杯"+name+"汁分给"+i+"个人喝");
}
//调用方法
syso("几杯");
int b = input.nextInt();
syso("什么水果");
String n = input.next();
syso("几人用餐");
int p = input.nextInt();
xx.getFruit(b,n,p);
public void getFruit(int l,String n){
syso("我是方法重载");
}
引用数据类型作为形参
基本数据类型的形参 接收了实参后 形参和实参没有任何关系
引用数据类型的形参 接收的是实参的地址 二者共享空间 修改任意一方的【属性】 两者都会变化
如果修改的是地址 则二者再没有关系
public class User{
String name;
int age;
public String toString(){
return name+" "+age;
}
}
public class Impl{
public void m1(int n){
n+=5;
syso(n); //
}
public void m2(User u){
//u接收的是测试类中uu1的地址
//u = new User();
u.name = "老妖精";
u.age = 100;
syso(u); //老妖精 100
}
public User getUser(String name){
for(User u : us){//增强for循环 赋给u的就是一个元素的地址
if(u.getName().equals(name)){
return u;//返回地址
}
}
return null;//地址
}
}
//测试类
Impl u = new Impl();
int nn = 10;
u.m1(nn); //15
syso(nn); //10
User uu1 = new User();
uu1.name = "张三";
uu1.age = 18;
syso(uu1); //张三 18
u.m2(uu1); //老妖精 100
syso(uu1); //老妖精 100
User uu = u.getUser("老妖精");//地址传递
if(uu==null){
syso("不存在");
}else{
uu.name = "老妖精";
}
构造方法
定义:返回所属类的对象的方法 可以借助构造方法 一边创建对象 一边给属性赋值
执行时机:new对象时调用
语法:1.没有返回值 包括不写 void 2.方法名就是类名
注意:
1.任何一个类 都有一个【默认的】【隐式的】【空参构造】
2.默认隐式空参构造 会被编写的带参构造覆盖 ==》习惯先编写出空参构造
3.构造方法调用构造方法 使用this(实参参数列表)
4.如果构造方法调用了其他构造方法 调用语句(this(参数))必须是该方法第一句话
5.构造方法互相调用时 必须保证有一个出口
6.构造方法和普通方法 也可以调用 但是要注意不要互相调用 防止堆栈溢出错误StackOverflowError
7.子类构造方法调用父类构造方法 需要使用super关键字 super(参数列表)
8.即使子类没有显式调用父类构造方法 依然默认调用父类空参构造 super() 注意保证父类的空参构造存在且可调用
9.子类构造方法 调用父类构造方法的语句 必须是该代码块的第一句话 所以 一个子类的构造方法 不能同时调用父类构造super(参数列表)和本类其他构造this(参数列表)
在创建子类对象前 一定会创建一个属于该子类对象的父类对象
public class User{
public String name;
public int age;
public double score;
public User(){
syso("我是空参构造");
}
//一旦编写有 带参构造方法 默认隐式空参构造就会失效
public User(String name,int age){
this();
this.name = name;
this.age = age;
}
public User(String name,int age, double score){
//this(name,age); //必须是该构造方法的第一句话
this.name = name;
this.age = age;
this.score = score;
}
}
//测试类中
User u = new User();//报错 默认隐式空参构造 因为带参构造的出现 而失效
syso("请输入姓名");
String name = input.next();
syso("请输入年龄");
int age = input.nextInt();
syso("请输入积分");
double score = input.nextDouble();
u.name = name;
u.age = age;
u.score = score;
User u = new User(name,age,score);
代码块
1.普通代码块
在方法中 划一对大括号
划分一个作用域
2.静态代码块
在类中 划一对大括号 添加static关键字
程序一运行就要执行的业务 可以放入其中 只执行一次
3.构造代码块
在类中 划一对什么都不加的大括号
每new一次对象 就会执行一次构造代码块 且优先于构造方法 可以有多组 当new对象时 从上往下全部执行
4.同步代码块
多线程中使用
静态代码块只执行一次
构造代码块每new一个对象 执行一次 所有构造代码块都要执行
构造方法每new一个对象 都要执行对应的那个构造方法
测试类静态代码块
父类静态代码块
子类静态代码块
父类构造代码块
父类构造方法
子类构造代码块
子类构造方法
public class Pet{
}
public class Dog extends Pet{
}
//测试类Test
public class Test{
{
}
public Test(){
}
main(){
Dog d = new Dog();
//Test t = new Test(); 如果没有创建测试类对象 则不执行测试类构造代码块 构造方法
//如果创建了测试类对象 就要看顺序
}
}
6子类构造代码块
7子类构造方法
3子类静态代码块
4父类构造代码块
5父类构造方法
2父类静态代码块
主类构造代码块
主类构造方法
1主类静态代码块
main(){
new 子类对象()
}
评论