面向对象的概念以及特征
概念
实质上将 "数据" 与 "行为" 的过程, 以类的形式封装起来, 一切以对象为中心语言。
面向对象的程序设计过程中有两个重要概念:类(class)和对象(也称为实例)。
其中类是某一批对象的抽象,可以把类理解成某种概念,相当于一种“模板”;
对象才是一个具体存在的实体,从这个意义上来看,日常所说的人,其实都是人的实例,而不是人类。
面向对象的核心特征
(1) 封装
封装是将数据和操作数据的方法捆绑在一起,形成对象。这样可以保护对象的数据不被外界直接访问和修改,而是通过对象提供的公共接口来进行操作。封装可以降低系统的复杂性,并使系统更加稳定和可靠。
(2) 继承
继承允许开发者创建新的类(子类),这个新类可以继承已有类(父类)的属性和方法。子类可以重用父类的代码,并且可以在不需要重新编写原有类的情况下对其进行扩展。继承体现了从一般到特殊的关系,例如,一个具体的汽车类可以继承自通用的交通工具类。
(3) 多态
多态是指不同的对象可以接收相同的消息,但每个对象可以以不同的方式响应该消息。多态允许同一个接口对应多个不同的实现,从而增加了代码的灵活性和可扩展性。例如,一个名为drive()
的方法可以被不同的车辆类实现,每种车辆都可以有自己的drive()
实现。
类的定义
- -使用class修饰类
- -类用于描述某种概念,封装类的静态特征以及动态特征
- -定义属性(成员变量、静态特征)
- -定义动态特征(行为方法)
类与实例,实例对象的创建
- -类是抽象的
- -对象是真实存在的
- -对象的创建是通过类的构造器new出来的
- -引用类型有多少种?无数种
//定义一个person类,类中包括属性与方法
public class Person {
//属性
String name;
String sex;
int age;
void eat() {//无参数的eat方法
System.out.println("干饭");}
void sleep() {
System.out.println("水饺");}
void play() {
System.out.println("玩");}
}
//创建对象,调用person类,初始化属性以及调用其方法
public class Object {
public static void main(String[] args) {
Person p;//创建 p 这个person类
p=new Person();//初始化 p
p.name="张三";//p的属性的初始化
p.sex="男";
p.age=77;
System.out.println(p.name);
System.out.println(p.sex);
System.out.println(p.age);
p.eat();//调用p 的eat方法
}
}
package和import语句
全限定名 package+类名
package的命名规则:一般为公司域名倒写/项目前缀;
例如:com.baidu.xxx(这里的xxx一般为某个模块/层次)
包名也为路径划分,例如:
//通过全限定类型约束当前类为com. day1027中的Person
com.day1027.Person p1 = new com.day1027.Person();
系统导入(import)
import java.util.*;// 导入java.until这个包里的所有类
import java.util.Arrays;//导入java.until这个包里面的Arrays类
1) 系统会默认导入同一个包中的类
2) 系统会默认导入java.lang.*; (可以在jdk/jre/lib/rt.jar中找到这个包)
位置关系
1)package语句在java源文件中的第一行
2)import语句在package和class之间
方法
定义
- -用于封装某种特殊的功能操作,能够进行入参和返回数据
组成元素
修饰符,方法返回值,方法名,方法参数,方法体
//定义一个方法,给某个小孩送礼物,要求获取姓名
public String songLiWu(String liwu){
//public 为修饰符,String为返回值类型,songLiWu为方法名,String liwu为参数,{}包含的为方法体
System.out.pringln("给小孩送了"+liwu);
return "小明";
}
方法的语法
举例:我给水果店老板50元,老板要给我称50元的水果,然后把水果交给我(买水果)
修饰符 方法的返回值 方法名(方法的参数列表) {
方法体(买水果的过程)
收了我50元
称50元的水果
返回水果
}
有返回值
在调用方法后需要返回该类型的数据;必须要加return语句。
--返回值类型为基本数据类型(8种)
则需要注意,返回数据的类型要比定义的返回值类型小或者相等 比如:方法返回值类型为double 则可以返回比double类型小的数据(long、int......)
//两数相加的和,返回结果
//如果返回值类型为基本数据类型,可以返回该类型所兼容的数据
int add(int a,int b) {
return a+b;
}
--返回值类型为引用类型
则返回该类型的对象或者该子类的对象
//如果返回值类型为引用类型,可以返回该类或者该子类的对象数据
Object buy(double money) {
return 12;//自动装箱 基本数据类型装箱为Integer
}
无返回值
使用void来表示当前方法没有返回值类型
//吃饭没有返回值类型
void eat() {
system.out.println( "吃饭");
}
方法签名
组成:由方法名与参数列表组成。(参数列表得看数据的类型是否相同,若数据类型相同,但变量名不同,仍然为同一个方法)
方法签名和修饰符、返回值类型没有关系。只要方法签名不一致,则不是同一个方法
//方法的id==方法签名--》【方法名+参数列表】
int add(int a,int c) {
return a;
}
int add(int a){//这两个方法并不是同一个方法
return a;
}
练习
1、商品分类:Category
属性:--分类id--分类名称--商品列表 方法:用于获取当前商品分类最top的销量的商品的方法getTopSlaeProdution();
2、商品:Prodution
属性:--商品编号--商品名称--商品价格--商品的总销量【销售额:元】 方法:用于打印当前商品的所有信息printMessage()
//商品分类Category
public class Category {
// 属性:--分类id--分类名称--商品列表
int id;
String name;
Prodution[] produtions;
// 方法:用于获取当前商品分类最top的销量的商品的方法getTopSlaeProdution();
Prodution getTopSlaeProdution() {
// 定义一个变量用于存放销量最高的商品
Prodution top = produtions[0];
// 遍历
for (Prodution prodution : produtions) {
// 判断,比较,把销量高的拿出来
if (prodution.saleNum > top.saleNum) {
top = prodution;
}
}
// 返回销量最高的商品
return top;
}
//商品类Prodution
public class Prodution {
// 属性:--商品编号--商品名称--商品价格--商品的总销量【销售额:元】
int code;
String name;
double price;
int saleNum;
// 方法:用于打印当前商品的所有信息printMessage()
void printMessage() {
System.out.printf("当前商品编码%d,名称为:%s,价格:%f,销量%d \n", code, name, price, saleNum);
}
//测试类
public static void main(String[] args) {
// 调用getTopSlaeProdution方法,获取当前商品分类的最top的销量的商品,并显示该商品信息
//主--商品分类 谓--调用 宾--getTopSlaeProdution方法 结果--销量的商品
//1、创建多个商品
Prodution p1 = new Prodution();
p1.name = "秋裤";
p1.saleNum = 100;
Prodution p2 = new Prodution();
p2.name = "卫衣";
p2.saleNum = 1100;
Prodution p3 = new Prodution();
p3.name = "内裤";
p3.saleNum = 10000;
Prodution p4 = new Prodution();
p4.name = "外套";
p4.saleNum = 500;
//2、创建商品分类、将多个商品赋值到商品分类中的列表
Category category = new Category();
category.name = "衣服";
category.produtions = new Prodution[]{p1,p2,p3,p4};
//3、调用方法
Prodution top = category.getTopSlaeProdution();
top.printMessage();//调用方法,显示商品信息
}
方法的入参匹配
不同类型匹配的优先级(从高到低)
基本数据类型
转换优先级:本类型--> 类型的提升顺序 --> 本类型的包装类 -->本类型的可变长度类型
引用类型
本类型-->父类
//方法的入参匹配
public static void main(String[] args) {
// 方法调用按照方法签名来调用
MethodInputInvoke invoke = new MethodInputInvoke();
//方法调用--方法签名
invoke.input(1,2);
//基本数据类型:本身--》类型提升--》包装类型--》长度可变类型
//引用类型:本身--》父类
//在同一个类中,同一种行为的不同的体现
//方法名相同,但是方法参数列表不同的
}
public class MethodInputInvoke {
//方法的组成元素 修饰符 返回值类型 方法名 方法参数列表 方法体
/*void input(byte i) {
System.out.println("byte i----------------------------");
}
void input(short i) {
System.out.println("short i----------------------------");
}
void input(int i) {
System.out.println("int i----------------------------");
}
void input(long i) {
System.out.println("long i----------------------------");
}*/
void input(Integer i) {
System.out.println("Integer i----------------------------");
}
void input(Short i) {
System.out.println("Short i----------------------------");
}
//参数入参个数是可变的 int...
void input(int... i) {
System.out.println("int... i----------------------------");
}
重载方法的定义
1.同一个类中
2.方法名相同
3.参数列表不同
4.方法的重载和修饰符以及方法返回值是没有关系的,只跟方法签名有关系
练习
定义Hero类
这四个参数分别是 heroName(英雄名), heroHP(英雄HP),heroArmor(英雄攻击力), heroMoveSpeed(移动速度)
互为重载方法:
--自己治疗的方法heal【自己增加100HP】
--给一个队友治疗的方法heal【队友增加200HP】
//思路
//1.定义Hero类--定义属性--定义两个方法
public class Hero {
// heroName(英雄名) heroHP(英雄HP) heroArmor(英雄攻击力) heroMoveSpeed(移动速度)
String heroName;
int heroHP;
int heroArmor;
int heroMoveSpeed;
//--自己治疗的方法heal【自己增加100HP】
void heal() {
heroHP = heroHP+100;
}
//--给一个队友治疗的方法heal【队友增加200HP】
void heal(Hero h) {//heal方法重载
h.heroHP = h.heroHP+200;
}
}
//2.测试类--创建对象--调用方法--输出结果
public class HeroTest {
public static void main(String[] args) {
// 孙悟空治疗自己
Hero sun = new Hero();
sun.heroName ="孙行者";
sun.heroHP = 1500;
System.out.println(sun.heroHP);
//
sun.heal();
System.out.println(sun.heroHP);
// 小明治疗孙悟空
Hero xiaoming = new Hero();
xiaoming.heroName ="小明";
//
xiaoming.heal(sun);
System.out.println(sun.heroHP);
}
}
方法的递归
定义:一个方法重复调用自身。主要解决问题1、方法的出口 -2、递归的规律
练习
题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子对数为多少?
程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21....;求13个月后,如兔子都不死,兔子对数为多少
public class Raq {
//方法 n表示为月份
int growp(int n) {
//1、出口
if(n<=2) { //第一、二个月固定数量
return 1;
}else {
//2、迭代 fum(n)= fum(n-1)+ fum(n-2) 当前月的数量等于前两个月的和
return growp(n-1)+growp(n-2);
}
}
//内部测试代码,要加static
//外部测试代码则不用
public static void main(String[] args) {
//
Raq ra = new Raq();
//
System.out.println(ra.growp(13));
}
}
构造器的定义
定义
作用是创建对象。其最大用处就是在创建对象时执行初始化。构造器也是一个特殊的方法 ,因为构造器没有返回值类型
语法
[修饰符] 类名(参数类别){
方法体}
如果一个类中没有定义构造器,则系统会默认提供一个无参构造器,但是如果有定义任意一个构造器,则系统不再提供无参构造器,所以通常来说在一类中要有一个无参构造器和一个有参构造器。
(注意:一般在类中定义构造器【无参和全参】【抽象类、接口、继承时会调用父类的无参构造器;在框架中会调用无参构造器】)
成员变量默认初始化
引用变量默认为null ;基本数据类型默认为0 ;布尔类型默认为false;
练习
现有:
班级:班级编号、班级名、学生列表,班主任,班长
方法:统计学生住址地点的方法,返回学生的住址地点
//分析:类--》属性--》方法--》测试
//班级Clazz--班级编号、班级名、学生列表,班主任,班长
//学生Student--姓名,住址地点
public class Clazz {
//-- 班级编号、班级名、学生列表
String code;
String name;
Student[] students;
//--班主任
Teacher teacher;
//--班长
Student monitor;
public Clazz() {//无参构造器
}
public Clazz(String n,Student[] stus) {//有参构造器
name=n;
students=stus;
}
//统计学生住址地点的方法,返回学生的住址地点
String[] getStuAddress() {
//1\创建一个数组,用于存放地址
String[] adds = new String[students.length];
//2\遍历学生,把地址存放到adds中
for(int i=0;i<students.length;i++) {
adds[i] = students[i].address;
}
//3\返回数组
return adds;
}
}
//学生类
public class Student {
// 外貌--属性--静态特征
String name;
String address;
String sex;
// 行为--方法--动态特征
// 构造器本质是一个特殊的方法【不需要返回值类型、方法名和类名一致】
// 无参构造器
public Student() {
}
public Student(String n,String a) {
name=n;
address=a;
}
//全参构造器:在创建对象的同时,给成员变量赋值
public Student(String n,String s,int a) {
name=n;
sex=s;
age=a;
}
}
//测试类
public class ClazzTest {
public static void main(String[] args) {
// 统计班级中学生的地址信息
// 提供学生
Student stu1 = new Student("zhang", "gz");
Student stu2 = new Student("li", "sz");
Student stu3 = new Student("wang", "zh");
// 提供班级
Clazz clazz = new Clazz("春田花花幼儿园", new Student[] { stu1, stu2, stu3 });
// 调用班级的方法,得到地址信息
String[] adds = clazz.getStuAddress();
// 遍历显示地址
for (String string : adds) {
System.out.println(string);
}
}
}
对象创建的内存分析
- 定义引用类型变量在main方法栈,而对象是在堆内存中创建的。
- 初始化有默认值,赋值就是把默认值给覆盖了。
- 方法只有调用的时候,才会入方法栈,用完便会释放出栈。