Java面向对象(超详细)

面向对象

前言

因为面向对象是一块大部分,所以我分开讲了,这篇讲类和成员,上一篇讲的方法,后面讲三大特征,最后讲抽象类和接口等。

了解一下什么是面向对象?

面向对象是一种编程的思想,编程的方式。这种编程的方式是以“类和对象”为中心。

与它同等级别的其他编程思想还有:面向过程、面向函数、面向切面、面向服务编程。

经常被放在一起对比的是面向过程与面向对象。

面向过程:以“过程”为中心,以步骤或函数为最小基本单位。

面向对象:以“类和对象”为中心,以“类”为最小基本单位。

例如:把大象装进冰箱问题的解决?

面向过程:

  • 第一步:把冰箱门打开
  • 第二步:把大象装进去
  • 第三步:把冰箱门关上

面向对象:

  • 这里有几个对象参与?
    • 冰箱、大象、人
  • 冰箱有什么特征,有什么功能,需要完成什么事
class 冰箱{
    String brand;
    double length;
    double width;
    double height;
    
    打开(){
        
    }
    关闭(){
        
    }
    储存(){
        
    }
}
class 大象{
    String type;
    double weight;(){
        
    }
}
class{
    push(){
        if(东西 是 冰箱){
            冰箱.关闭();
        }else if(东西是大象){
            大象.();
        }
    }
    pull(东西){
        if(东西 是 冰箱){
            冰箱.打开();
        }else if(东西是大象){
            大象.();
        }
    }
}

怎么把它们整合起来

public class 主类{
    public static void main(String[] args){
        人 r = new("张三");
        冰箱 b = new 冰箱("美的",5,5,10);
        大象 d = new 大象("亚洲",2);
        
        r.pull(冰箱);
        r.pull(大象);
        r.push(大象);
        r.push(冰箱);
    }
}

问你什么是面向对象的思想?

  • 找到合适的类及其对象,来解决我们的当前问题。如果核心类库中,或者第三方的类库中,有现成的类,就直接拿来用。如果没有这个合适的类,就新定义一个类,然后再用它。

什么是类和对象?

类:一类具有相同特性的事物的抽象描述。现实生活中,我们也会对事物进行分类管理。

相同特征:

  • 基本信息,就是属性,数据,例如:姓名、年龄、电话、邮箱、性别等
  • 能力或功能,就是方法,例如:学习能力,教学能力

如何声明一个类?

  • 类名的命名规范:大驼峰命名法,每一个单词首字母大写,尽量见名知意。
【修饰符】 class 类名{
    
}

对象:对象是这一类事物的具体的个体或实体

public class Student{//一个类
    
}
Student s1 = new Student("张三",23,'男');//具体的一个对象

先有类还是先有对象呢?

  • 从系统的设计和分析的角度来说,先有对象再有类,先观察需求中各个对象的共同特征,抽取出类
  • 从实际编码的角度来说,必须先写类,才能new对象

类与对象的关系是什么?

  • 类是创建对象的模板,设计图。比喻:造汽车的设计图。

  • 对象是类的一个具体的实例(instance),实体,个体。比喻:具体的一辆能开的车。

如何new对象?

new 类名()  //匿名对象
类名 对象名 = new 类名(); //有名字的对象

//对象名就是变量名而已
//变量的概念范围更大,不是所有变量都是引用对象的
//int a = 1; a也是变量,但它不是对象
//Student s = new Student(); s是变量,它引用一个对象,它才是对象名

什么是包?

在操作系统层面,或资源管理器的层面,包就是文件夹。

在Java语法的层面,包就是类的限定名。

为什么要用包?

  • 方便管理众多的类
  • 避免类的重名,有了包之后,类的全名称就是 包.类名
    • 例如:String的全名称是 java.lang.String
    • 例如:Scanner的全名称 java.util.Scanner
  • 结合权限修饰符来限定某些类或类的成员的可见性范围
    在这里插入图片描述

如何定义/声明包?

从代码的角度来说:

注意:代码必须与资源管理器的目录结构对应,对不上就会报错。

package 包名;

在这里插入图片描述

IDEA中如何创建包?
在这里插入图片描述在这里插入图片描述

包的命名规范
在这里插入图片描述

如何跨包使用类?

  • 这个类必须public才能跨包使用
  • 必须加import语句或使用类的全名称
    • 同一个类名的,只能有一个import语句。如果两个类同名,属于不同的包,只能一个import,一个使用全名称。或者两个都用全名称。

类的成员之一:成员变量

什么是成员变量?

定义在类中,但是在方法外的变量称为成员变量。

public class 类名{
    【修饰符】 数据类型 变量名;  //成员变量
    
    【修饰符】 返回值类型 方法名(【形参列表】){ //形参也是局部变量
        数据类型 变量名;      //局部变量
    }
}

在这里插入图片描述
在这里插入图片描述

成员变量的分类

静态变量:

  • 有static修饰的成员变量,就是静态变量。又称为类变量。

实例变量:

  • 没有static修饰的成员变量,就是实例变量。有的时候称为属性(笼统的说,所有的实例变量都可以叫做属性,但是更专业的说,有get/set方法才叫属性)。
package com.gj.pkg.field;

public class Employee {
    public static String company; //公司      因为有static,所以它是静态变量
    public String name; //姓名                因为没有static,所以它是实例变量
    public int age;//年龄                     因为没有static,所以它是实例变量
}

如何访问成员变量

  • 跨类使用
静态变量实例变量
跨类使用类名.静态变量(标准用法)对象名.实例变量
package com.gj.pkg.field;

public class TestEmployee {
    public static void main(String[] args) {
        System.out.println("===========默认值============");
        System.out.println(Employee.company);//null

        //实例就是对象,只有通过对象才能访问实例变量
        Employee e1 = new Employee();
        System.out.println(e1.name);//null
        System.out.println(e1.age);//0

        System.out.println("===========赋值============");
        Employee.company = "尚硅谷";
        e1.name ="张三";
        e1.age = 23;

        System.out.println(Employee.company);//尚硅谷

        System.out.println(e1.name);//张三
        System.out.println(e1.age);//23

        Employee e2 = new Employee();
        System.out.println(e2.name);//null
        System.out.println(e2.age);//0

        System.out.println(e1.company);//非标准用法,有警告
        System.out.println(e2.company);//非标准用法,有警告

    }
}
  • 本类使用
静态变量实例变量
本类使用既可以在本类的静态方法中用,又可以在本类的实例方法中用,没有限制只能在本类的非静态方法中使用

成员变量的特点

所有成员变量都有默认值

  • byte,short,int,long:0
  • float,double:0.0
  • char:\u0000的空字符
  • boolean:false
  • 引用数据类型(包括String,数组等):null

值的独立性和共享性

静态变量实例变量
独立性和共享性所有对象共享的每一个对象都是独立的

成员变量的内存分析

变量的本质就是代表一块内存区域,用于存储数据的。内存应该有内存地址,但是不便于记忆,需要给内存取名字,变量名就是给内存取名字。

变量有三要素:变量名、数据类型、变量值。数据类型决定了变量所占用的内存大小。
在这里插入图片描述

一个对象在堆中的内存分为3个部分:

  • 对象头:用于存储对象所属类的指针、对象的hashcode值、锁标记、GC标记等(今天不讨论)
  • 实例数据区:用于存储对象的实例变量的值
  • 填充空白(不是所有对象都有的):当某些类有boolean类型的变量时,1个boolean的变量占二进制的1位,但是内存管理是以“字节“为单位,当我们有1个boolean值后,1个字节就会有7位是空的,那么为了内存的”对齐“管理方便,这7位就是填充空白。
    在这里插入图片描述
    在这里插入图片描述

成员变量是引用数据类型

案例1
在这里插入图片描述

package com.gj.pkg.field;

public class Husband {//丈夫类
    public String name;
    public Wife wife;
    //Wife在这里是数据类型,是类(class)类型
}
package com.gj.pkg.field;

public class Wife {//妻子类
    public String name;
    public Husband husband;
    //Husband也是数据类型,是类(class)类型
}
package com.gj.pkg.field;

public class TestHusbandWife {
    public static void main(String[] args) {
        Husband h = new Husband();
        h.name = "光头强";

        Wife w = new Wife();
        w.name = "翠花";

        h.wife = w;//翠花嫁给光头强
        w.husband = h;//光头强娶翠花

        System.out.println("丈夫的姓名:" + h.name +",他的妻子的姓名:" + h.wife.name);
        System.out.println("妻子的姓名:" + w.name +",她的丈夫的姓名:" + w.husband.name);
    }
}

在这里插入图片描述

案例2

com.gj.exer5包中

(1)声明一个MyDate类型,有属性:年year(int类型),月month(int类型),日day(int类型)

(2)在测试类TestMyDate类中,创建两个日期对象,一个日期赋值为今年六一儿童节日期,一个日期赋值为今年程序员节日期,并显示

(3)声明另一个Employee类型,有属性:姓名name(String类型),生日birthday(MyDate类型)

(4)在测试类TestEmployee中的main中,创建两个员工对象,并为他们的姓名和生日赋值,并显示

package com.gj.exer5;

/*
(1)声明一个MyDate类型,有属性:年year(int类型),月month(int类型),日day(int类型)
 */
public class MyDate {//日期类
    public int year;
    public int month;
    public int day;
    //它们是成员变量,没有static修饰,所以也叫实例变量
}
package com.gj.exer5;

public class TestMyDate {//测试类

    public static void main(String[] args) {
        //创建两个日期对象,一个日期赋值为今年六一儿童节日期,
        // 一个日期赋值为今年程序员节日期,并显示
        MyDate m1 = new MyDate();
        m1.year = 2024;
        m1.month = 6;
        m1.day = 1;

        MyDate m2 = new MyDate();
        m2.year = 2024;
        m2.month = 10;
        m2.day = 24;

        //输出信息
        System.out.println("今年的六一儿童节:" + m1.year + "年" + m1.month + "月" + m1.day + "日");
        System.out.println("今年的程序员节:" + m2.year + "年" + m2.month + "月" + m2.day + "日");
    }

}
package com.gj.exer5;

/*
(3)声明另一个Employee类型,有属性:姓名name(String类型),生日birthday(MyDate类型)
 */
public class Employee {
    public String name;
    public MyDate birthday;

}
package com.gj.exer5;

public class TestEmployee {
    public static void main(String[] args) {
        //创建两个员工对象,并为他们的姓名和生日赋值,并显示
        Employee e1 = new Employee();
        e1.name = "熊大";
//        e1.birthday = new MyDate();//只要是引用数据类型的变量,就可以给它赋值对应类型的对象
        /*
        (1)编译时(javac命令),由编译器来检查语法格式等
        这里编译没有报错,
        ①是因为e1这个变量是Employee类型的,然后e1可以.出name和birthday,因为Employee类定义了这两个成员变量
        .有个专业的名称,称为成员操作符,用来访问“成员”
        ②e1.birthday也是变量,是MyDate类型的,它能.出year、month、day,
        因为MyDate类定义了这3个成员变量
        ③语法正确,再看数据类型
        2000,1,9都是整数,可以给year,month,day,因为它们也是int类型
        (2)运行时(java命令)
        运行时就要检查e1,birthday这些.前面的变量是否有对象
         */

        e1.birthday.year = 2000;
        e1.birthday.month = 1;
        e1.birthday.day = 9;

        Employee e2 = new Employee();
        e2.name = "熊二";
        MyDate m2 = new MyDate();
        m2.year = 2001;
        m2.month = 5;
        m2.day = 8;
//        e2.birthday = m2;

        //输出员工的信息
        System.out.println("员工的姓名:" + e1.name +",生日:" + e1.birthday.year+"年" + e1.birthday.month+"月" + e1.birthday.day+"日");
        System.out.println("员工的姓名:" + e2.name +",生日:" + e2.birthday.year+"年" + e2.birthday.month+"月" + e2.birthday.day+"日");

    }
}

在这里插入图片描述

类的成员之二:成员方法

成员方法的分类

静态方法

  • 如果有static修饰的方法,就是静态方法,又称为类方法。

实例方法

  • 没有static修饰的方法,就是实例方法,通常也称为非静态方法。

思考:什么时候该用静态方法,什么时候该用实例方法呢?

原则:如果方法中只访问静态变量(或者扩大的话,只访问本类的静态成员),那么这个方法可以是是静态方法,也可以是实例方法

​ 但是如果方法中涉及到访问实例变量(或者扩大的话,设计到访问本类的其他非静态成员),那么这个方法必须实例方法

package com.gj.pkg.method;

public class Account {//银行账号
    public static double rate;//年利率
    public String id;//卡号
    public double balance;//余额
    //上面的3个成员变量中,rate是静态变量,id和balance是实例变量
    //实例变量依赖于对象

    //定义方法,返回利息,利息的简单算法是 利息 = 余额 * 利率
    //因为这个方法中涉及到实例变量balance,这个方法只能是实例方法,不能是静态方法
    public double getInterest(){
        return balance * rate;
    }

    //定义方法,返回月利率,月利率的简单算法 = 年利率 ÷ 12
    //因为这个方法中不涉及实例变量等其他非静态成员,那么这个方法可以是静态的,也可以是非静态的
    //一般如果这个方法是工具类性质的方法,一般选静态的,否则选非静态的
    //例如:数学工具类Math类,数组工具类Arrays,集合工具类Collections等,它们中全部是静态方法
    //这个并没有语法上严格的界限,定义为静态方法更方便
    public static double getMonthlyRate(){
        return rate / 12;
    }
}
package com.gj.pkg.method;

public class TestAccount {
    public static void main(String[] args) {
        Account.rate = 0.35;
        System.out.println("月利率:" + Account.getMonthlyRate());

        //System.out.println("利息:" + Account.getInterest());//报错,没有对象
        //实例方法,实例变量等依赖于对象

        Account a = new Account();
        a.id = "1111111";
        a.balance = 100000000000L;
        System.out.println("a账号的余额:" + a.balance +",利息:" + a.getInterest());
        //a账号的余额:1.0E11,利息:3.5E10科学计数法
    }
}

如何调用方法

  • 跨类调用
静态方法实例方法/非静态方法
跨类调用类名.方法(【实参】)对象名.方法(【实参】)
  • 本类调用
静态方法实例方法/非静态方法
本类调用随便用只能在其他非静态方法中使用

同一个类中成员互相使用的总结

在这里插入图片描述

再次体会为什么要用方法?

方法是一个独立的可复用的功能。换句话,当一段代码需要反复被使用,就可以封装为一个方法。

案例1

写法1:没有定义方法

package com.gj.pkg.method;

public class Rectangle {//矩形,长方形
    public double length;//长
    public double width;
}
package com.gj.pkg.method;

public class TestRectangle1 {
    public static void main(String[] args) {
        Rectangle r1 = new Rectangle();
        r1.length = 8;
        r1.width = 6;

        Rectangle r2 = new Rectangle();
        r2.length = 10;
        r2.width = 5;

        double area1 = r1.length * r1.width;
        double area2 = r2.length * r2.width;

        double perimeter1 = (r1.length + r1.width) * 2;
        double perimeter2 = (r2.length + r2.width) * 2;

        System.out.println("r1的长:" + r1.length +",宽:" + r1.width +",面积:" + area1 +",周长:" + perimeter1);
        System.out.println("r2的长:" + r2.length +",宽:" + r2.width +",面积:" + area2 +",周长:" + perimeter2);
    }
}

写法2:声明方法

package com.gj.pkg.method;

public class Rectangle {//矩形,长方形
    public double length;//长
    public double width;

    public double area(){
        return length * width;
    }

    public double perimeter(){
        return 2 * (length + width);
    }

    public String getInfo(){
        return "长:" + length +",宽:" + width +",面积:" + area() +",周长:" + perimeter();
    }
}
package com.gj.pkg.method;

public class TestRectangle1 {
    public static void main(String[] args) {
        Rectangle r1 = new Rectangle();
        r1.length = 8;
        r1.width = 6;

        Rectangle r2 = new Rectangle();
        r2.length = 10;
        r2.width = 5;

        System.out.println("r1的" + r1.getInfo());
        System.out.println("r2的" + r2.getInfo());
    }
}

案例2

package com.gj.pkg.method;

/*
(1)声明一个MyDate类型,有属性:年year(int类型),月month(int类型),日day(int类型)
 */
public class MyDate {//日期类
    public int year;
    public int month;
    public int day;
    //它们是成员变量,没有static修饰,所以也叫实例变量

    public void setDate(int y, int m, int d){
        year = y;
        month = m;
        day = d;
    }

    public String getDateInfo(){
        return year + "年" + month + "月" + day + "日";
    }
}
package com.gj.pkg.method;

public class TestMyDate {//测试类

    public static void main(String[] args) {
        //创建两个日期对象,一个日期赋值为今年六一儿童节日期,
        // 一个日期赋值为今年程序员节日期,并显示
        MyDate m1 = new MyDate();
        m1.setDate(2024,6,1);

        MyDate m2 = new MyDate();
        m2.setDate(2024,10,24);

        //输出信息
        System.out.println("今年的六一儿童节:" + m1.getDateInfo());
        System.out.println("今年的程序员节:" + m2.getDateInfo());
    }

}
package com.gj.pkg.method;

/*
(3)声明另一个Employee类型,有属性:姓名name(String类型),生日birthday(MyDate类型)
 */
public class Employee {
    public String name;
    public MyDate birthday;

    public void setEmployeeInfo(String n, int y, int m, int d){
        name = n;
        birthday = new MyDate();
        birthday.year = y;
        birthday.month = m;
        birthday.day = d;
    }

    public String getEmployeeInfo(){
//        return "姓名:" + name +",生日:" + birthday.year+"年" + birthday.month+"月" + birthday.day+"日";//对
        return "姓名:" + name +",生日:" + birthday.getDateInfo();
    }
}
package com.gj.pkg.method;

public class TestEmployee {
    public static void main(String[] args) {
        //创建两个员工对象,并为他们的姓名和生日赋值,并显示
        Employee e1 = new Employee();
        e1.setEmployeeInfo("熊大",2000,1,9);

        Employee e2 = new Employee();
        e2.setEmployeeInfo("熊二",2001,5,8);

        //输出员工的信息
        System.out.println("员工1的" + e1.getEmployeeInfo());
        System.out.println("员工2的" + e2.getEmployeeInfo());
    }
}

成员小结

静态变量与实例变量

静态变量实例变量
有没有static
内存位置方法区
共享还是独立共享独立
初始化时机类加载后就初始化new对象时初始化
本类中谁能用它静态方法 + 实例方法实例方法
其他类如何用它类名.静态变量对象名.实例变量

静态方法和实例方法

静态方法实例方法/非静态方法
有没有static
本类中谁能用它静态方法 + 实例方法实例方法
其他类如何用它类名.静态方法对象名.实例方法
在本类中它能用谁只能用本类的静态变量,静态变量可以使用本类的所有成员:静态变量、静态方法、实例变量、实例方法

面向对象三大基本特征oop

封装:将属性和方法打包成一个对象,同时利用public protect 缺省 private修饰符来隐藏对象的内部实现细节,只暴露必要的公共接口供外部访问。这样做的好处可以保护对象不被外界随意修改,增加安全性。

继承:允许子类可以继承父类的成员变量和成员方法。复用父类的代码,同时可以扩展自己特有的功能。减少了代码重复,使得程序结构更加清晰和模块化。

多态:一个方法的多种形态,多态有两种形式,编译时多态:方法重载,运行时多态:方法重写。运行时多态的具体表现形式是父类或接口的引用指向子类对象,编译时候看左边父类或接口类型来确定我要调用哪个方法,运行时看等号右边实际对象类型决定调用哪个方法实现。这样编写代码更灵活,扩展性强。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值