当前位置: 首页 > news >正文

【JAVA 核心编程】面向对象中级:封装与访问控制

一、包

1)包的本质

实际上就是创建不同的文件夹来保存类文件

2)包的命名

只能包含数字,字母,下划线,小圆点,但不能用数字开头,不能是关键字或保留字

一般是小写字母+小圆点

3)常用的包

java.lang.*//lang包是基本包,默认引用,不需要再引入java.util.*//util包,系统提供的工具包,工具类,使用Scannerjava.net.*//网络包,网络开发java.awt.*//是做java界面的界面开发,GUI

4)引用的包

语法:import 包

import java.util.Arrays;
public class Main{public static void main(String[] args){int[] arr = {-1,20,2,19,5};Arrays.sort(arr);for(int i = 0;i < arr.length;i++)System.out.print(arr[i] + "\t");}
}

5)注意事项和使用细节

  • package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package
  • import指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求

二、访问修饰符

四种访问修饰符

1.公开级别:用public 修饰,对外公开

2.受保护级别:用protected修饰,对子类和一个包中的类公开

3.默认级别:没有修饰符号,向同一个包的类公开

4.私有级别:用private 修饰,只有类本身可以访问,不对外公开

在这里插入图片描述

三、封装

1)封装介绍

封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。

2)封装好处

  1. 隐藏实现细节:方法(连接数据库)<–调用(传入参数.)
  2. 可以对数据进行验证,保证安全合理
Person {name, age}
Person p = new Person();
p.name = "jack";
p.age = 1200;

3)封装的实现步骤

  1. 将属性进行私有化private 【不能直接修改属性】
  2. 提供一个公共的(public)set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){//Xxx 表示某个属性//加入数据验证的业务逻辑属性 = 参数名;
}
  1. 提供一个公共的(public)get方法,用于获取属性的值
public 数据类型 getXxx(){ //杈限判断,Xxx 某个属性return xx;
}

4)get与set

1.灵活性

比如我们有一个Person类,我们给它设置一个属性name,但是我们希望在取名字的时候,不是只显示名字,而是把名字按我们的要求输出,比如”我的名字叫XX”
我们只要定义一个person对象,并给他setName(xx),再getName的时候,就会显示我的名字叫XX。在实际业务中还可以有更灵活的运用,这里就不举例了。

2.安全性

只读,还是只写,还是可读写,这里的读写就好比get/set。
对于类来说,如果直接用public定义某个属性,那么这个属性是可读可写的,如果你希望一个类的某个属性是只能读取,不能写入的时候,上面用public定义某个属性就不能满足了,我们可以使用private定义属性,再定义一个get方法,但是不定义set方法来实现。反之,只定义set,不定义get则表示该属性是只写不能读的。

public class Main {public static void main(String[] args) {Person person = new Person();person.setName("jack2222222");person.setAge(22);person.setSalary(30000);System.out.println(person.infp());}
}//函数封装
class Person{public String name;;private int age;;private double salary;public String getName() {return name;}public void setName(String name) {if(name.length() >=2 && name.length() <= 6){this.name = name;}else{System.out.println("名字长度不对,需要(2-6)个字符,默认无名人");this.name = "无名人";}}public int getAge() {return age;}public void setAge(int age) {if(age>=1&&age<=120){this.age = age;}else{System.out.println("年龄需要在1-120");this.age = 18;//设置默认年龄}}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public String infp(){return name + age + salary;}
}

5)封装与构造器

public class Main {public static void main(String[] args) {Person person = new Person();person.setName("jack2222222");person.setAge(22);person.setSalary(30000);System.out.println(person.infp());Person smithwww = new Person("smithwww", 28, 2000);System.out.println(smithwww.infp());}
}//函数封装
class Person{public String name;;private int age;;private double salary;//添加构造器public Person(){}****************************************************public Person(String name, int age,double salary ) {//这样并不能起到防护机制/*this.salary = salary;this.age = age;this.name = name;*///所以将set方法写在构造器中。仍可以验证数据,起到防护机制setName(name);setAge(age);setSalary(salary);}****************************************************public String getName() {return name;}public void setName(String name) {if(name.length() >=2 && name.length() <= 6){this.name = name;}else{System.out.println("名字长度不对,需要(2-6)个字符,默认无名人");this.name = "无名人";}}public int getAge() {return age;}public void setAge(int age) {if(age>=1&&age<=120){this.age = age;}else{System.out.println("年龄需要在1-120");this.age = 18;//设置默认年龄}}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public String infp(){return name + age + salary;}
}

6)实例

public class Main {public static void main(String[] args) {Account account = new Account();account.setName("jack");account.setBalance(500);account.setPwd("243567");account.Showfo();}
}
//函数封装
class Account{private String name;private double balance;private String pwd;public String getName() {return name;}public void setName(String name) {if(name.length() >= 2 && name.length() <= 4){this.name = name;}else{System.out.println("名字格式不对,默认姓名为HELL");this.name = "HELL";}}public String getPwd() {return pwd;}public void setPwd(String pwd) {if(pwd.length() == 6){this.pwd = pwd;}else{System.out.println("密码格式不对,默认密码123456");this.pwd = "123456";}}public double getBalance() {return balance;}public void setBalance(double balance) {if(balance > 0){this.balance = balance;}else{System.out.println("余额不足");this.balance = 0;}}public void Showfo() {System.out.println("姓名:" + name + " 余额:" + balance + " 密码:" + pwd);}
}

四、继承

提出代码复用的问题:

我们编写了两个类,一个是Pupil 类(小学生),一个是Graduate(大学毕业生)问题:

两个类的属性和方法有很多是相同的,怎么办?
=> 继承(代码复用性~)

1)继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维,

当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,

所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。画出继承的示意图
在这里插入图片描述

继承的基本语法
class 子类 extends 父类{
}
1)子类就会自动拥有父类定义的属性和方法.
2)父类又叫 超类,基类。
3)子类又叫派生类。

2)简单示例

主函数

package D412;public class testExtend {public static void main(String[] args) {Pupil pupil = new Pupil();pupil.name = "银角大王";pupil.age = 18;pupil.testing();pupil.setScore(50);pupil.showInfo();Graduate graduate = new Graduate();graduate.name = "金角大王";graduate.age = 20;graduate.testing();graduate.setScore(80);graduate.showInfo();}
}

父类 student 类

package D412;public class Student {//共有属性public String name;public int age;private double score;//共有方法public void setScore(double score){this.score = score;}public void showInfo(){System.out.println("Name: " + name + " Age: " + age + " Score: " + score);}
}

子类

pupil类
package D412;//让 Pupil 继承 Student 的类
public class Pupil extends Student {public void testing(){System.out.println("小学生 " + name + "正在考小学数学..");}
}
package D412;public class Graduate extends Student{public void testing() {System.out.println("大学生 " + name + " 正在考大学数学..");}
}

3)继承的细节

1.子类继承了所有的属性和方法,非私有的属性和方法可以直接访问,但是私有属性不能在子类直接访问,要通过公共的方法去访问。

package D417;public class Extends {public static void main(String[] args) {Sub sub = new Sub();sub.sayOK();}
}

父类

package D417;public class Base {public int n1 = 100;protected int n2 = 200;int n3 = 300;private int n4 = 400;public Base() {System.out.println("base()...");}//父类提供一个public的方法,返回了一个n4public int getN1() {return n4;}public void test100() {System.out.println("test100");}protected void test200() {System.out.println("test200");}void test300() {System.out.println("test300");}private void test400() {System.out.println("test400");}public void calltest400(){test400();}
}

子类

package D417;public class Sub extends Base {public Sub() {System.out.println("sub(....");}public void sayOK(){//我们发现父类的非private属性和方法都可以访问System.out.println(n1+" "+n2+" "+n3+" ");test100();test200();test300();//test400();错误//通过父类提供公共的方法去访问System.out.println("n4 = "+ getN1());calltest400();}
}

2.子类必须调用父类的构造器,完成父类的初始化。

3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。

4.如果希望指定去调用父类的某个构造器,则在子类显式的调用一下:super(参数列表)

5.super在使用时,需要放在构造器第一行

6.super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

7.java所有类都是Object类的子类,Object是所有类的基类

8.父类构造器的调用不限于直接父类!将一直往上追溯到Object类(顶级父类)

9.子类最多只能继承一个父类(直接继承),java中是单继承类

10.不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

五、super用法

  • 调用父类的构造器的好处 (分工明确,父类属性由父类初始化,子类的属性由子类初始化)

  • 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名使用super、this、直接访问是一样的效果![举例]

  • super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则

super代表父类的引用,用于访问父类的属性,方法,构造器

1.访问父类的属性,但不能访问父类的private属性

super.属性名;

2.访问父类的方法,不能访问父类的private方法

super.方法名(参数列表);

3.访问父类的构造器

super(参数列表);

只能放在构造器的第一句,只能出现一句!

//希望调用父类-A的cal方法//这时,因为子类B没有cal方法,因此我可以使用下面三种方式
//找cal方法时,顺序是:
//(1)先找本类,如果有,则调用
//(2)如果没有,则找父类(如果有,并可以调用,则调用)
//(3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 0bject类
//提示:如果查找方法的过程中,找到了,但是不能访问,则报错,cannot access11如果查找方法的过程中,没有找到,则提示方法不存在
cal();
this.cal(); //等价 cal
super.cal();// 找cal方法的顺序是直接査找父类,其他的规则一样,直接跳过子类

在这里插入图片描述

六、多态

1.方法或对象具有多种形态,多态是建立在封装和继承基础之上的。

2.对象的多态

(1)一个对象的编译类型与运行类型可以不一样

(2)编译类型在定义对象时,就确定了,不能改变

(3)运行类型时可以变化的

(4)编译类型看定义时 = 号的左边,运行类型看 = 号右边

Animal animal = new Dog();【animal 编译类型是Animal,运行类型Dog)

animal = new Cat();【animal 的运行类型变成了 Cat, 编译类型仍然是 Animal)

1)向上转型

多态的前提是:

两个对象(类)存在继承关系多态的向上转型

  1. 本质:父类的引用指向了子类的对象

  2. 语法:父类类型引用名 = new 子类类型();

  3. 特点:编译类型看左边,运行类型看右边。可以调用父类中的所有成员(需遵守访问权限);
    不能调用子类中特有成员;最终运行效果看子类的具体实现!

Animal animal  = new Cat();

2)向下转型

  1. 语法:子类类型 引用名 = (子类类型) 父类引用;

  2. 只能强转父类的引用,不能强转父类的对象

  3. 要求父类的引用必须指向的是当前目标类型的对象

  4. 可以调用子类类型中所有的成员

Cat car = (Cat) animal;

#属性没有重写之说!属性的值看编译类型

3)instanceof 比较操作符

用于判断对象的运行类型是否为XX类型或XX类型的子类型

4)java动态访问机制

1.当调用对象方法的时候,该方法和该对象的内存地址/运行类型绑定。

2.当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。

5)多态数组

1.概述:多态数组,需要满足数组类型定义为父类类型,而里面保存的实际元素类型为子类类型(可同时存放多种子类)。实际达到的效果就是父类引用指向子类对象。2.使用:多态数组在使用时往往与instanceof关键字配合使用。即在遍历数组时,通过增加 if条件语句进行判断,使得不同类型的子类对象元素可以分别使用它们各自的特有方法。

七、Object类

1)equals

在这里插入图片描述

既可以判断基本类型,又可以判断引用类型
如果判断基本类型,判断的是值是否相等。示例:int i=10; double d=10.0;
如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象【案例说明】

IDEA查看jdk源码

File -> Project Structure ->SDKs ->Sourcepath 然后点击右侧绿色的加号

Object类,只能判断引用类型
//默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等如何重写equals方法
应用实例: 判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样;
则返回true,反之false
public class Equals01 {public static void main(String[] args) {A a = new A();A b = a;A c = b;System.out.println(a == c);//trueSystem.out.println(b == c);//trueB bObj = a;System.out.println(bObj == c);//trueint num1 = 10;double num2 = 10.0;System.out.println(num1 == num2);//基本数据类型,判断值是否相等//equals 方法,源码怎么查看. //把光标放在 equals 方法,直接输入 ctrl+b/*//带大家看看 Jdk 的源码 String 类的 equals 方法//把 Object 的 equals 方法重写了,变成了比较两个字符串值是否相同public boolean equals(Object anObject) {if (this == anObject) {//如果是同一个对象return true;//返回 true}if (anObject instanceof String) {//判断类型String anotherString = (String)anObject;//向下转型int n = value.length;if (n == anotherString.value.length) {//如果长度相同char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {//然后一个一个的比较字符if (v1[i] != v2[i])return false;i++;}return true;//如果两个字符串的所有字符都相等,则返回 true}}return false;//如果比较的不是字符串,则直接返回 false}*/"hello".equals("abc");//看看 Object 类的 equals/*//即 Object 的 equals 方法默认就是比较对象地址是否相同//也就是判断两个对象是不是同一个对象. public boolean equals(Object obj) {return (this == obj);}*//*//从源码可以看到 Integer 也重写了 Object 的 equals 方法, //变成了判断两个值是否相同public boolean equals(Object obj) {if (obj instanceof Integer) {return value == ((Integer)obj).intValue();}return false;}*/Integer integer1 = new Integer(1000);Integer integer2 = new Integer(1000);System.out.println(integer1 ==integer2);//falseSystem.out.println(integer1.equals(integer2));//trueString str1 = new String("hspedu");String str2 = new String("hspedu");System.out.println(str1 ==str2);//falseSystem.out.println(str1.equals(str2));//true
}
}class B {
}class A extends B {
}

equals重写

Person person1 = new Person("jack",10,'男');
Person person2 = new Person("jack",10,'男');//判断两个person属性是否相等//重写0bject 的 equals方法
public boolean equals(object obj) {//判断如果比较的两个对象是同一个对象,则直接返回trueif (this == obj) {return true;}//类型判断if (obj instanceof Person) {//是Person,我们才比较//进行 向下转型,因为我需要得到obj的 符个属性Person p = (Person) obj;return this,name.equals(p.name) && this.age == p.age && this.gender == p.gender;}return false;
}

2)HashCode

在这里插入图片描述

1.提高具有哈希结构的容器效率

2.两个引用,如果指向的是同一个对象,则哈希值肯定一样

3.两个引用,如果指向的是不同对象,则哈希值是不一样的

4.哈希值主要根据地址号来,不能完全将哈希值等价于地址

3)toString

基本介绍默认返回:全类名+@+哈希值的十六进制,【查看Object 的 toString方法】

(1)子类往往重写toString方法,用于返回对象的属性信息

public string tostring(){return getclass().getName()+"@"+ Integer.toHexString(hashCode())}

(2)重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString

(3)当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用

monster.toString()

//重写后,一般把对象的属性输出
//快捷键 alt+insert ->toString
class Person{String name;int age;char gender;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", gender=" + gender +'}';}
}

4)finalize

finalize方法
//Finalize .java
1.当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法做一些释放资源的操作【演示】
2.什么时候被回收:当某个对象没有任何引用时,则ivm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
3.垃圾回收机制的调用,是由系统来决定,也可以通过System.gc()主动触发垃圾回收机制,测试:Car [name]

举例

import java.util.*;class RunoobTest extends GregorianCalendar {public static void main(String[] args) {try {// 创建 RunoobTest 对象RunoobTest cal = new RunoobTest();// 输出当前时间System.out.println("" + cal.getTime());// finalize calSystem.out.println("Finalizing...");cal.finalize();System.out.println("Finalized.");} catch (Throwable ex) {ex.printStackTrace();}}
}

八、断点调试

1)介绍

(1)重要提示: 在断点调试 过程中,是运行状态,是以对象的 运行类型来执行的。

A extends B : B b= new A(); b.xx();

(2)断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这-一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。进行分析从而找到这个Bug

(3)断点调试是程序员必须掌握的技能。

(4)断点调试也能帮助我们查看java底层源代码的执行过程,提高程序员的Java水平。

2)快捷键

F7:(跳入)跳入方法内
F8:(跳过)逐行执行代码
F9:(resume,执行到下一个断点)
shift+F8:跳出方法

在这里插入图片描述

http://www.dtcms.com/a/335975.html

相关文章:

  • 获取IPv6地址的三种方式
  • 【Git系列】如何从 Git 中删除 .idea 目录
  • Rust:实现仅通过索引(序数)导出 DLL 函数的功能
  • MySQL定时任务详解 - Event Scheduler 事件调度器从基础到实战
  • 学习Stm32 的第一天
  • 基于RK3588的微电网协调控制器:实现分布式能源的智能调控与优化运行
  • git stash临时保存工作区
  • 因果知识图谱:文本预处理的革命性突破
  • pytest中使用loguru的问题及解决
  • CF2121C Those Who Are With Us
  • Week 12: 深度学习补遗:RNN与LSTM
  • Vue 与 React 深度对比:设计哲学、技术差异与应用场景
  • Zemax 中的透镜设计 - 像差理论
  • Python | 解决 matplotlib 中文乱码
  • CentOS7安装部署GitLab社区版
  • 从需求到部署全套方案:餐饮服务许可证数据可视化分析系统的大数据技术实战
  • 深入浅出全面理解贝叶斯框架(Bayesian Framework)
  • jinja2模板引擎全面解析
  • Python3字符串全面指南:从基础操作到40个内建函数实战
  • Go语言并发编程 ------ 锁机制详解
  • 深入理解 uni-app 页面导航:switchTab、navigateTo、redirectTo、reLaunch 与 navigateBack
  • 2.4 双向链表
  • QUIC浅析
  • 流浪循环 全DLC(Rogue Loops)免安装中文版
  • 超市电商销售分析项目:从数据分析到业务决策
  • 【架构师从入门到进阶】第五章:DNSCDN网关优化思路——第十一节:网关安全-对称与非对称加密
  • PHP静态类self和static用法
  • 【计算机视觉与深度学习实战】04基于K-Means聚类的图像分割系统设计与实现
  • Java Stream 初解
  • 14.web api 5