Java面向对象:封装、继承

三. 面向对象

  • IDEA的使用:
    1. 新建工程:New Project -> Empty Project(最后一项),IDEA中project相当于eclipse中workspace

    2. 自动弹出Project structure窗口,先取消掉

    3. 在空的工程下新建Module(模块):File -> new -> Moudle,IDEA中模块类似于eclipse中的project

    4. 选择Java,点击next,给module命名

    5. 在src上右键 -> New -> Java Class,创建类

    IDEA字体设置:File -> Settings -> 输入font搜索,设置字体大小及样式 ->Apply -> Ok
    快速生成main方法:psvm + 回车
    快速生成System.out.println();:sout + 回车
    IDEA是自动保存,不需要Ctrl + s
    删除一行:Ctrl + y
    运行:代码上右键run或者点击绿色三角,或Ctrl + Shift + F10
    左侧目录栏键盘控制:左箭头收起,右箭头展开,上下键移动
    IDEA中退出任何窗口都可以用Esc键
    新增/新建/添加的快捷键:Alt + insert,然后输入来查找
    窗口变大/变小:Ctrl + Shift + F12
    java代码界面间切换:Alt + 左箭头/右箭头
    切换窗口:Alt + 标号
    提示方法参数:Ctrl + p
    查看访问的属性/方法:按住Ctrl,点击左键;查看所有属性/方法:Ctrl + o
    单行注释:Ctrl + / 多行注释:Ctrl + Shift + /
    纠错快捷键:alt + 回车
    多行注释:Ctrl + shift + /
    查看类的属性、方法:Ctrl + F12

  • 面向对象特征:封装

  • 封装的好处:

    1. 封装之后,对事物来说看不到复杂的一面,只能看到该事物简单的一面。复杂性封装,对外提供简单的操作入口
    2. 封装之后才会形成真正的“对象”、真正的“独立体”
    3. 封装意味着程序可以重复使用,且适用性更强
    4. 封装后提高了事物的安全性
public class User{		//没有进行封装
	int age;		//User类中的age属性在外部程序中可以随意访问,导致age属性不安全
}

public class UserTest{
	public static void main(String[] args){
		User user = new User();
		System.out.println(user.age);		//输出0
		user.age = -100;
		System.out.println(user.age);
		//输出-100,age不可能为负,而在运行时并未报错
	}
}
  • 封装的步骤:

    1. 所有属性私有化,使用private关键字修饰,private表示私有,修饰的所有数据只能在本类中访问

    2. 对外提供简单的操作入口,提供两个公开的方法,分别是set方法和get方法

      读取数据:调用get方法

      修改属性:调用set方法

    3. set方法命名规范:(接上例)

      public void setAge (int a){
      ​ age = a;
      }

    4. get方法命名规范:

      public int getAge (){
      ​ return age;
      }

    5. setter和getter方法没有static关键字

      调用有static关键字修饰的方法:类名.方法名(实参);

      没有static关键字修饰的方法调用方法:引用.方法名(实参);

public class User{
	private int age;
}

public calss UsterTest{
	User user = new User();
	System.out.println(user.age);		//编译报错,age属性私有化,外部程序不能直接访问
}

public class User{
	private int age;
	public void setAge(int age){
		age = age;		//编译报错
	}
	public void setAge(int a){		//setter
		age = a;
	}
	public int getAge(){		//getter
		return age;
	}
}

public class UserTest{
	public static void main(String[] args){
		User user = new User();
		user.setAge(-100);		//修改
		System.out.println(user.getAge());		//读取,依然可以是负数
	}
}
//修改setAge方法:
public void setAge(int a){
	if(a < 0 || a > 150){		//加入判断
		System.our.println("年龄不合法");
		return;
	}else{
		age = a;
	}
}
  • 关于Java中的构造方法:
    1. 构造方法又被称为构造函数/构造器/Constructor

    2. 构造方法语法结构:

      [修饰符列表] 构造方法名 (形式参数列表) {
      ​ 构造方法体;
      }

    3. 普通方法语法结构:

      [修饰符列表] 返回值类型 方法名 (形式参数列表) {
      ​ 方法体;
      }

    4. 对于构造方法来说,“返回值类型”不需要指定,也不能写void(带返回值类型的是普通方法)

    5. 构造方法的方法名必须和类名保持一致

    6. 构造方法的作用:通过构造方法的调用,可以创建对象(同时初始化实例变量的内存空间)

    7. 构造方法的调用:

      1. 普通方法调用:(有static修饰符)类名.方法名(实参列表);
        没有static修饰符:引用.方法名(实参列表);

      2. 构造方法调用:new 构造方法名(实参列表);

    8. 每一个构造方法执行结束后都有返回值(返回值类型为构造方法所在类的类型),但是“return 值;”语句不用写

    9. 当一个类中没有任何方法时,系统会默认给该类提供一个无参数的构造方法,该构造方法称为缺省构造器

    10. 当一个类定义了构造方法,系统不再提供缺省构造器(建议为当前类提供无参数构造方法,无参数构造方法常用)

public class User{
}
public class UserTest{
	public static void main(String[] args){
		new User();		//编译通过
	}
}

public class User{
	public User(){
		System.out.println("abc");
	}
}
public class UserTest{
	public static void main(String[] args){
		new User();		//输出abc
	}
}

public class User{
	public User(){		//无参数构造方法
		System.out.println("User's Default ConsTructor Invoke!")
	}
	//有参数的构造方法
	public User(int i){
		System.out.println("带有int类型参数的构造器")
	}
	public User(String name){
		System.out.println("带有String类型参数的构造器")
	}
	public User(int i,String name){
		System.out.println("带有int,String类型的构造器")
	}
}
public class UserTest{
	public static void main(String[] args){
		User u1 = new User();		//以下程序创建了4个对象,在“堆内存”中开辟空间
		User u2 = new User(10);
		User u3 = new User("abc");
		User u4 = new User(10,"abc");
	}
}
public class Account {
    private String actno;
    private double balance;
    public Account(){}		//无参数构造方法
    public Account(String a){
        actno = a;
    }
    public Account(double b){
        balance = b;
    }
    public Account(String c,double d){
        actno = c;
        balance = d;
    }
    public String getActno() {
        return actno;
    }
    public void setActno(String actno) {
        this.actno = actno;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
}

public class UserTest {
    public static void main(String[] args){
        Account a1 = new Account();
        System.out.println(a1.getActno());		//null
        System.out.println(a1.getBalance());		//0.0
        Account a2 = new Account("abc");
        System.out.println(a2.getActno());		//abc
        System.out.println(a2.getBalance());		//0.0
        Account a3 = new Account(100.0);
        System.out.println(a3.getActno());		//null
        System.out.println(a3.getBalance());		//100.0
        Account a4 = new Account("abc",100.0);
        System.out.println(a4.getActno());		//abc
        System.out.println(a4.getBalance());		//100.0
    }
}
  • 参数传递

    调用方法时参数传递的是变量中保存的具体值(不是传地址)

public class Test01 {
    public static void add(int i){
        i ++;
        System.out.println(i);		//输出11
    }
    public static void main(String[] args) {
        int i = 10;
        add(i);						//等同于add(10);
        System.out.println(i);		//输出10
    }
}

参数传递时,java只遵循一种语法机制:传递变量中保存的值,只是有时这个值是字面值,有时这个值是另一个java对象的内存地址

public class Test01 {
    public static void main(String[] args) {
        User u = new User(20);		//User u = 0x1234
        add(u);		//等同于add(0x1234),传递u的值(u保存的是对象的地址)
        System.out.println(u.age);		//21
    }
    static void add(User u) {
        u.age++;
        System.out.println(u.age);		//21
    }
}
class User {
    int age;		//实例变量
    public User(int i) {		//构造方法
        age = i;
    }
}
  • this关键字
    1. this是一个关键字,意为:这个
    2. this是一个引用/变量,this变量中保存了内存地址指向自身,this存储在JVM堆内存java对象内部
    3. 每创建一个对象就有一个this
    4. this可以出现在“实例方法”中,指向当前执行动作的对象
    5. this不能使用在带有static关键字的方法中
  • 没有static关键字的方法称为“实例方法”,使用“引用.”访问

    没有static关键字的方法称为“实例变量”

  • 当一个行为/动作执行过程中需要对象参与时,该方法要定义为“实例方法”,不能带static

public class Customer {
    String name;
    public Customer(){		//顾客购物的行为,不带static关键字的方法
    //由于每一个对象在执行购物动作时结果不同,所以购物动作必须有“对象”的参与
    }
    public void shopping(){
        System.out.println(this.name + "在购物");
    //由于name是一个实例变量,所以name访问时一定是当前对象的name
    //所以多数情况下“this.”可以省略:System.out.println(name + "在购物");
    }
    public static void doSome(){
    	System.out.println(this.name);		//编译错误,执行过程中没有“当前对象”
    	//无法从静态上下文中引用非静态 变量 name
    	//与之前学的“变量作用域”内容有不同
    }
}

public class CustomerTest {
    public static void main(String[] args) {
        //在对象内部生成this变量,存储内容与c1相同,都指向对象
        Customer c1 = new Customer();
        c1.name = "zhangsan";
        Customer c2 = new Customer();
        //使用c2访问对象时,过程中出现的this就是c2
        c2.name = "lisi";
        System.out.println(c1.name);		//输出zhangsan
        System.out.println(c2.name);		//输出lisi
        c1.shopping();		//调用shopping方法,输出zhangsan在购物
        c2.shopping();		//输出lisi在购物
    }
}
public class abc {
	int i = 10;		//实例
    public static void main(String[] args) {
    	abc.doSome();	//编译错误,带有static的方法中不能“直接”访问实例变量和实例方法
    	System.out,println(i);	//编译错误,必须用“引用.”的方式访问
        abc a = new abc();
        a.run();
    }
    public void doSome(){
        System.out.println("do some");
    }
    public void run(){
        System.out.println("run");
        doSome();       //编译通过,意为调用当前对象的doSome方法
        //run是实例方法,调用时一定存在对象,此处省略了“this.”
    }
}
  • 用来区分局部变量和实例变量时,“this.”不能省略
public class User {
    private int id;
    public void setId(int id) {
    	//this不能省略
        this.id = id;       //this.id是实例变量,等号后边的id是局部变量id
    }
    public User(int id,String name){
    	this.id = id;		//this不能省略
    	this.name = name;
    }
}
  • 用于构造方法:通过当前构造方法调用其他构造方法

    语法格式:this(实参);

    this()语法只能出现在构造函数第一行(一个构造方法中只能出现一次)

public class Date {
    private int year;
    private int month;
    private int day;
    public Date(){      //需求:调用无参数构造方法时,默认日期为“1970-1-1”
        this(1970,1,1);     //不创建对象,又能调用其它构造方法
    }
    public Date(int year,int month,int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public static void main(String[] args) {
        Date d1 = new Date();
        Date d2 = new Date(1998,1,22);
        System.out.println(d1.year + "年" + d1.month + "月" + d1.day + "日");
        System.out.println(d2.year + "年" + d2.month + "月" + d2.day + "日");
    }
    //setter和getter方法省略
}
  • 练习题
public class test01 {
    int i = 10;
    public static void doSome(){
        System.out.println("do some");
    }
    public void doOther(){
        System.out.println("do other");
    }
    public static void method1(){
        test01.doSome();		//完整调用static方法
        doSome();		//省略调用static方法
        test01 doother = new test01();
        doother.doOther();		//编译成功
        this.doOther();		//编译报错:无法从静态上下文中引用非静态变量
        System.out.println(doother.i);
    }
    public void method2(){
        test01.doSome();
        doSome();
        test01 other = new test01();
        other.doOther();
        doOther();		//编译通过
        System.out.println(other.i);
        System.out.println(i);
    }

    public static void main(String[] args) {
        test01.method1();
        method1();
        test01 test = new test01();
        test.method2();
    }
}
  • 带有static的方法,既可以用“类名.”的方式访问,也可以用“引用.”的方式访问

    采用引用方式调用,执行时与引用所指向的对象无关,程序会出现警告

public class test {
    public static void doSome(){
        System.out.println("do some");
    }
    public static void main(String[] args) {
        test.doSome();
        doSome();
        test t = new test();
        t.doSome();
        t = null;       //不构成空指针异常
        t.doSome();
    }
}
  • static关键字
    1. static修饰的方法是静态方法,static修饰的变量是静态变量
    2. 所有static修饰的元素都是静态的,可以用“类名.”访问,也可以用“引用.”访问(不推荐)
    3. static修饰的元素都是类级别的特征,与具体对象无关
  • 成员变量声明为实例变量:所有对象都有该属性,且不同对象属性不同

  • 成员变量声明为静态变量:所有对象都有该属性,且所有对象属性相同

  • 静态变量在类加载时初始化,在方法区开辟内存,访问时不需要创建对象

public class Chinese {
    String id;
    String name;
    String country;
    //static String country;     所有对象国籍相同,属于整个模板的特征,创建为静态变量
    public Chinese(){}
    public Chinese(String id,String name,String country){
    //public Chinese(String id,String name);
        this.id = id;
        this.name = name;
        this.country = country;
        System.out.println(this.id + this.name + this.country);
        //可以改为System.out.println(this.id + this.name + Chinese.country);
    }
    public static void main(String[] args) {
        Chinese zhangsan = new Chinese("1","zhangsan","China");
        //Chinese zhangsan = new Chinese("1","zhangsan");
        Chinese lisi = new Chinese("2","lisi","China");
        //Chinese lisi = new Chinese("2","lisi");
    }
}
  • 可以用static关键字定义“静态代码块”:

    1. 语法格式:
static{
	java语句;
}
  1. 静态代码块在类加载时执行,且只执行一次
  2. 静态代码块在一个类中可以编写多个,遵循自上而下的顺序依次执行
  3. 用途:例如要求在类加载时完成日志记录(静态代码块执行时刻为类加载时刻)
  4. 通常在静态代码块中完成预备工作,完成数据的准备工具(例如:初始化连接池、解析XML配置文件)
public class Static01 {
    static {
        System.out.println("类加载1");		//输出顺序:1
    }
    static {
        System.out.println("类加载2");		//输出顺序:2
    }
    public static void main(String[] args) {
        System.out.println("主方法");		//输出顺序:3
    }
}
  • 实例语句块/实例代码块(很少用)
    1. 实例代码块可以编写多个,自上而下依次执行
    2. 实例代码块在构造方法执行前执行,构造方法执行一次,实例代码块也对应执行一次
    3. 实例代码块执行的时机被称为对象初始化时机
public class StaticTest {
    public StaticTest(){        //构造函数
        System.out.println("缺省构造器");		//输出顺序:4
    }
    {       //实例代码块
        System.out.println(1);		//输出顺序:2
    }
    {
        System.out.println(2);		//输出顺序:3
    }
    public static void main(String[] args) {
        System.out.println("main");		//输出顺序:1
        new StaticTest();
    }
}
  • 重新理解System.out.println(String[] args);主方法
    1. public表示公开的,在任何位置都能访问
    2. static表示静态的,使用“类名.”方式即可访问
    3. void表示main方法执行结束后返回值类型为空
    4. main是main方法的方法名
    5. (String[] args)是main方法的形参列表
public class Main {
    public static void main(int i) {		//方法重载
        System.out.println(i);
    }
    public static void main(String args) {
        System.out.println(args);
    }
    public static void main(String[] args) {
        Main.main(10);		//输出10
        Main.main("hello world");		//输出hello world
    }
}
  • 静态方法:

    方法描述的是动作,当不同对象执行某一动作结果相同时,该动作提升为类级别/模板级别的动作

    静态方法中无法直接访问实例变量和实例方法

public class StsticTest01 {
    int i;		//实例变量
    public void doSome(){		//实例方法
    }
    public static void main(String[] args) {		//静态方法(静态上下文)
        System.out.println(i);		//编译失败
        doSome();		//无法从静态上下文中引用非静态 方法
    }
}

​ “工具类”一般使用静态方法:

public class Math {
    public static int sum(int a,int b){
        return a + b;
    }
    public static int divide(int a,int b){
        return a / b;
    }
    public static void main(String[] args) {
        System.out.println(sum(10,20));
        System.out.println(divide(40,20));
    }
}
  • 面型对象特征:继承

    1. 继承的“基本”作用:代码复用。继承最“重要”的作用:有了继承才有以后“方法的覆盖”和“多态机制”
    2. 继承语法格式:
[修饰符列表] class 类名 extends 父类名{
	类体 = 属性 + 方法
}
  1. java中的继承只支持单继承,一个类只能继承一个类,不能同时继承多个类(在c++中支持多继承)

  2. 继承中的术语:(若B类继承A类)

    A类称为:父类、基类、超类、superclass

    B类称为:子类:派生类、subclass

  3. 子类继承父类的数据:私有数据、构造方法不继承,其他数据都可以被继承

  4. 虽然java只支持单继承,但一个类也可以间接继承其他类,例如:

C extends B{}
B extends A{}
A extends T{}		//C类直接继承B类,但是C类间接继承T、A类
  1. java中假设一个类没有显示继承任何类,该类默认继承JavaSE库中的java.lang.Object类
public class ExtendsTest {		//这个类没有定义任何方法
    public static void main(String[] args) {
        ExtendsTest a = new ExtendsTest();
        String b = a.toString();		//编译通过
        //说明该类继承了Object类,可以调用toString方法
        System.out.println(b);		//输出ExtendsTest@1b6d3586
    }
}
  • 继承举例:
public class Account {
    private String no;
    private double balance;
    public Account() {}
    public Account(String no, double balance) {
        this.no = no;
        this.balance = balance;
    }
    public String getNo() {
        return no;
    }
    public void setNo(String no) {
        this.no = no;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
}

public class CreditAccount extends Account{		//继承Account类的公开方法
    private double credit;
    public CreditAccount(String no, double balance, double credit) {
        super(no, balance);		//自动生成
        this.credit = credit;
    }
    public double getCredit() {
        return credit;
    }
    public void setCredit(double credit) {
        this.credit = credit;
    }
}

public class ExtendsTest {
    public static void main(String[] args) {
        CreditAccount act = new CreditAccount("001",100.0,99.9);
        System.out.println(act.getNo() + "," + act.getBalance() + "," + act.getCredit());		//输出001,100.0,99.9
    }
}
public class ExtendsTest0 {
    public static void main(String[] args) {
        C c = new C();
        c.doSome();		//这里调用的doSome方法是从B类中继承的
        //输出do some B
    }
}
class A{
    public void doSome(){
        System.out.println("do some A");
    }
}
class B extends A {
    public void doSome(){
        System.out.println("do some B");
    }
}
class C extends B {
}
  • 方法覆盖(override)
    1. 方法覆盖又被称为方法重写:override(官方)/overwrite
    2. 当父类中的方法无法满足子类的业务需求,子类有必要对父类继承来的方法重新编写,称为方法重写/方法覆盖
    3. 方法覆盖发生在具有继承关系的父子类之间,覆盖只针对方法,不谈属性
    4. 构成方法覆盖:返回值类型相同、方法名相同、形参列表相同
    5. 子类的方法访问权限不能更低,可以更高(若父类方法为public,子类在方法覆盖时只能是public)
    6. 抛出异常不能更多,可以更少
    7. 私有方法、构造方法不能继承,所以不能覆盖;静态方法不存在覆盖
public class Animal {
    public void move(){		//定义父类方法move
        System.out.println("动物会移动");
    }
}

public class Cat extends Animal{		//继承父类Animal
    public void move() {		//覆盖从Animal类继承来的move方法
        System.out.println("猫会跑");
    }
}

public class Bird extends Animal{
    public void move() {
        System.out.println("鸟会飞");
    }
}

public class Chicken extends Bird{		继承父类Bird
    public void move() {		//覆盖从Bird类继承来的move方法
        System.out.println("鸡不会飞");
    }
}

public class OverrideTest {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.move();		//调用对象a的move方法,输出动物会移动
        Cat c = new Cat();
        c.move();		//输出猫会跑
        Bird b = new Bird();
        b.move();		//输出鸟会飞
        Chicken ch = new Chicken();
        ch.move();		//输出鸡不会飞
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值