Java大数据开发和安全开发
(一)Java的封装
1.1 什么是封装
- 就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去
- 要处理的数据
- 处理数据的方法
- 写到一个类里就是封装 如下
1.1.1 封装的设计规范
- 合理隐藏
- 合理暴露
- private
public class Student {
private String name;
double chinese;
double math;
private void printTotalScore() {
System.out.println(name + "的总成绩是:" + (chinese + math));
}
public void printAverageScore() {
System.out.println(name + "的平均成绩是:" + (chinese + math) / 2.0);
}
}
怎么达到合理隐藏 合理暴露呢
控制输入
控制输出
为了防止别人随意传值,使用私有化变量,然后让用户通过公有方法访问给私有变量赋值
public class Student {
private String name; // 私有变量 不允许访问
private double score;
private double math;
public void setScore(String name,double score,double math){
if ((score >= 0 && score <= 100) && (math >=0 && math<=100)){
this.name = name;
this.score = score;
this.math = math;
} else {
System.out.println("数据非法");
}
}
public double getScore(){
return score;
}
private void printTotalScore() { // 私有方法 不允许访问
System.out.println(name + "的总成绩是:" + (chinese + math));
}
public void printAverageScore() {
System.out.println(name + "的平均成绩是:" + (chinese + math) / 2.0);
}
}
public class Test {
public static void main(String[] args) {
// 目标:掌握封装的设计规范:合理隐藏、合理暴露。
Student s1 = new Student();
s1.setScore("liyang",55,66);
System.out.println(s1.getScore());
}
}
1.1.2 代码层面如何控对象的成员公开或隐藏?
- 公开成员,可以使用public(公开)进行修饰。
- 隐藏成员,使用private(私有,隐藏)进行修饰。
1.2 JavaBean(实体类)
什么是实体类?
- 就是一种特殊形式的类。
1.2.1创建实体类
- 1.先创建两个私有变量
public class Student {
private String name;
private double score;
}
2.选中变量右键选择generate,可以创建有参构造器,set方法,get方法
- 3.无参构造方法选择selec none
public class Student {
//1、必须私有成员变量,并为每个成员变量都提供getset方法
private String name;
private double score;
//2、必须为类提供一个公开的无参数构造器
public Student() {
}
public Student(String name, double score) {
this.name = name;
this.score = score;
}
public void setName(String name) {
this.name = name;
}
public void setScore(double score) {
this.score = score;
}
public String getName() {
return name;
}
public double getScore() {
return score;
}
}
public class Test {
public static void main(String[] args) {
//目标:掌握实体类的书写要求、特点、应用场景
Student s1 = new Student();
s1.setName("播妞");
s1.setScore(99);
System.out.println(s1.getName());
System.out.println(s1.getScore());
}
}
1.2.2 实体类有啥应用场景?
- 实体类只负责数据存取,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离
操作类处理数据
public class StudentOperator {
private Student student;
public StudentOperator(Student student) {
this.student = student;
}
public void printPass() {
if (student.getScore() >= 60) {
System.out.println(student.getName() + "学生成绩及格");
} else {
System.out.println(student.getName() + "学生成绩不及格");
}
}
}
实体类保存数据
```java
public class Test {
public static void main(String[] args) {
//目标:掌握实体类的书写要求、特点、应用场景
Student s1 = new Student();
s1.setName("播妞");
s1.setScore(99);
System.out.println(s1.getName());
System.out.println(s1.getScore());
StudentOperator operator =new StudentOperator(s1);
operator.printPass();
}
}
1.2.3 实体类总结
- 什么是实体类?有啥特点?
- 成员变量必须私有,且要为他们提供get、set方法;必须有无参数构造器
- 仅仅只是一个用来保存数据的java类,可以用它创建对象,保存某个事物的数据。
- 实体类有啥应用场景?
- 实体类对应的是软件开发里现在比较流行的开发方式,数据和数据的业务处理相分离
1.3 继承
1.3.1 继承的语法格式
- Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。
继承的特点
- 子类能继承父类的非私有成员(成员变量、成员方法)
继承后对象的创建
- 子类的对象是由子类、父类共同完成的。
先写一个类A
public class A{
//公开成员
public int i;
public void print1(){
System.out.println("===print1===");
}
// 私有成员
private int j;
private void print2(){
System.out.println("===print2===");
}
}
再写一个类B继承A
// 子类
public class B extends A{
private int k;
//子类是可以继承父类的非私有成员
public void print3(){
System.out.println(i); //直接访问A的公开成员和方法
print1();
// System.out.println(j);
// print2();
那如果此时我们创建一个对象b 这个b可以继承那些东西?
此时的b是由A和B两个设计图共同创建的表,可以使用A和B的所有公开成员变量和方法
public class Test {
public static void main(string[] args){
// 目标:认识继承、掌握继承的特点。
B b = new B();
System.out.println(b.i);
// System.out.println(b.j);
// System.out.println(b.k);
b.print1();
//b.print2();
b.print3();
1.3.2 继承的执行原理
当创建一个B对象时,具体的过程如下:
- 类加载:JVM 会将A类和B类的字节码加载到方法区中。方法区存储了类的元数据,包括类的定义、常量、静态变量和方法。
- 实例化B对象:在堆内存中创建一个B对象的实例。堆内存用于存储对象的实例数据。
- 继承属性:B对象会继承A类的公开成员变量i。这意味着B对象具有A类的公开属性,可以直接访问和使用。
- 方法继承:B类继承了A类的公开方法print1。因此,B对象可以调用print1方法,就像它是自己的方法一样。
- 私有成员限制:由于j是A类的私有成员,根据 Java 的封装原则,子类(B)无法直接访问父类的私有成员。尝试访问b.j会导致编译错误。
- 子类特有属性:B类定义了自己的私有成员变量k,它是B类特有的,与父类A无关。
- 在方法区中,存储了类的信息,包括类的定义、方法和变量。方法区中的数据在程序运行期间是共享的。
- 栈内存用于方法调用和局部变量的存储。当调用B类的方法时,相关的方法参数和局部变量会被压入栈中。
- 堆内存用于存储对象实例。每个对象都有自己的内存空间,包括继承自父类的成员和子类自己定义的成员。
1、什么是继承?继承后有啥特点 ?
- 继承就是用extends关键字,让一个类和另一个类建立起一种父子关系。.
- 子类可以继承父类非私有的成员。
2、带继承关系的类,Java会怎么创建它的对象?对象创建出来后,可以直接访问哪些成员?
- 带继承关系的类,java会用类和其父类,这多张设计图来一起创建类的对象。
- 对象能直接访问什么成员,是由子父类这多张设计图共同决定的,这多张设计图对外暴露了什么成员,对象就可以访问什么成员。
1.3.3 使用继承有啥好处?
- 减少重复代码的编写。
继承的案列讲解
这两个类存在大量重复代码 怎么能简化一下,省去编写这么的重复代码的力气呢
那就是采用继承,让两个类继承重复的代码,然后直接调用
先新建一个People类
public class People {
private String name;
public string getName(){
return name;
}
public void setName(string name){
this.name = name;
}
在创建一个教师类继承People类
public class Teacher extends People{
private string skill;
public string getSkill(){
return skill;
}
public void setSkill(string skill){
this.skill = skill;
}
在创建一个咨询师类继承People类
public class ConsuIktant extends People{
private int number;
public int getNumber(){
return number;
}
public void setNumber(int number){
this.number = number;
}
在写一个Test类 使用main方法是作为Java 程序的入口点 调用其他方法等,从而控制程序的执行顺序和逻辑。
public class Test {
public static void main(string[]args){
// 目标:搞洁楚继承的好处。
Teacher t= new Teacher();
t.setName(“播仔");
t.setSkill("Java、Spring");
System.out.println(t.getName());
System.out.println(t.getskill());
t.printInfo();
}
}
1.3.4 继承的注意事项
1.3.4.1 权限修饰符
- 什么是权限修饰符?
- 就是是用来限制类中的成员(成员变量、成员方法、构造器、代码块…)能够被访问的范围。
- 权限修饰符有几种?各自的作用是什么?
编写一个修饰符的测试类
public class Fu {
// 1、私有:只能在本类中访问
private void privateMethod(){
System.out.println("==private==");
}
// 2、缺省:本类,同一个包下的类
void method(){
System.out.println("==缺省==");
}
// 3、protected:本类,同一个包下的类,任意包下的子
protected void protectedMethod(){
System.out.println("==protected==");
}
// 4、public: 本类,同一个包下的类,任意包下的子类,
public void publicMethod(){
System.out.println("==public==");
}
// 5、本类中测试调用不同修饰符的方法
public void test(){
privateMethod();
method();
protectedMethod();
publicMethod();
}
在同一个包类下的其他类调用不同修饰符的方法
public class Demo {
public static void main(string[]args){// 目标:掌握不同权限修饰符的作用。
Fu f = new Fu();
// f.privateMethod(); 不允许调用私有方法
f.method();
f.protectedMethod();
f.publicMethod();
}
}
在任意包下的子类
里调用不同修饰符的方法
public class Zi extends Fu {
public void test(){
// privateMethod();// 报错
// method();// 报错
protectedMethod();
publicMethod();
}
}
在任意包下的任意类里调用不同修饰符的方法
public class Demo2{
public static void main(string[] args){
Fu f = new Fu();
// f.privateMethod();// 报错
// f.method();// 报错
// f.protecedMethod();// 报错
f.publicMethod(); //完全暴露
}
}
1.3.4.2 单继承、0bject类
- Java是单继承的,Java中的类不支持多继承,但是支持多层继承
public class Test {
public static void main(String[]args){
//目标:掌握继承的两个注意事项事项。
// 1、Java是单继承的:一个类只能继承一个直接父类;Java中的类不支持多继承,但是支持多层继承。
//2、0bject类是Java中所有类的祖宗。
}
class A{}
class B extends A{}
class C extends B,A{} // 报错
class D extends B{} //D 继承B B继承A 这就是多层继承
}
为何Java中的类不支持多继承
请看如下反证法:
0bject类
object类是java所有类的祖宗类。我们写的任何一个类,其实都是object的子类或子孙类。
class A{}
//实际默认继承了0bject类
class A{}//extends 0bject{}
public class Test {
public static void main(String[]args){
//目标:掌握继承的两个注意事项事项。
// 1、Java是单继承的:一个类只能继承一个直接父类;Java中的类不支持多继承,但是支持多层继承。
//2、0bject类是Java中所有类的祖宗。
A a= new A();
a.如下图会自动显示多个方法 这些方法都是0bject类的
}
- B类就是0bject类的孙子类 B继承了A 继承了0bject类 B也就继承了0bject类
class A{}
class B extends A{}
B b = new B();
b.如下图会自动显示多个方法 这些方法都是0bject类的
- object类是java所有类的祖宗类。我们写的任何一个类,其实都是object的子类或子孙类。
1.3.4.3 方法重写
- 当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
- 注意:重写后,方法的访问,Java会遵循就近原则
方法重写的其它注意事项
- 重写小技巧:使用Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好,
- 子类重写父类方法时 访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)
- 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
- 私有方法、静态方法不能被重写,如果重写会报错的。
私有方法、静态方法不能被重写,如果重写会报错的。
方法重写在开发中的常见应用场景
子类重写0bject类的toString()方法,以便返回对象的内容
public class student extends 0bject{
private String name;
private int age;
public student(){
}
public Student(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
输出对象时默认调用的就是tostring 但是object类自带的toString方法返回的东西是内存地址,不是我们想要的
public class Test {
public static void main(string[]args){
// 目标:认识方法重写,掌握方法重写的常见应用场景。
Bb=new B();
b.print1();
b.print2( a:2,b:3);
System.out.println("-------------------------")
Students =new Student( name:"播妞",age: 19);
//System.out.println(s.tostring());
System.out.println(s); //输出对象时默认调用的就是tostring
@Override
public string tostring(){
return "Student{name=" + name + ",age=" + age + "}";
}
完整代码
public class student extends 0bject{
private String name;
private int age;
public student(){
}
public Student(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
@Override
public string tostring(){
return "Student{name=" + name + ",age=" + age + "}";
}
Student{name=播妞,age=19}
右键还可以自动生成重写代码 选择tostring
1.3.4.4 子类中访问其他成员的特点
1、在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的
- 先子类局部范围找。
- 然后子类成员范围找。
- 然后父类成员范围找,如果父类范围还没有找到则报错
2、如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法
- 访问重名的成员变量name 会就近选择方法内部的name
- 访问子类的变量就需要使用this.子类变量 访问父类 super.父类变量
就近原则
- 访问重名的成员方法
- 访问父类方法使用super.父类方法() 访问子类方法使用子类方法()
就近原则
1.3.4.5 子类构造器的特点
- 子类的全部构造器,都会先调用父类的构造器,再执行自己
class F{
public F(){
System.out.println("===父类F的 无参数构造器 执行了===");
}
class Z extends F{
public 2(){
// super();// 默认存在的
System.out.println("===子类Z的 无参数构造器 执行了===");
}
public Z(String name){
//super();// 默认存在的
System.out.println("===子类Z的 有参数构造器 执行了===");
}
public class Test{
public static void main(String[]args){// 目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景。
Z z= new Z();
Z z2= new Z( name:"播妞");
}
}
父类只有有参构造器了 ,子类的super会报错,要不想报错就让super调用有参构造器 super( name:“播妞”,age: 17);
class F{
//public F(){
//System.out.println("===父类F的 无参数构造器 执行了===");
//}
public F(String name,int age){
System.out.println("===父类F的 无参数构造器 执行了===");
}
class Z extends F{
public 2(){
// super();// 默认存在的
super( name:"播妞",age: 17);
System.out.println("===子类Z的 无参数构造器 执行了===");
}
public Z(String name){
//super();// 默认存在的
super( name:"播妞",age: 17);
System.out.println("===子类Z的 有参数构造器 执行了===");
}
public class Test{
public static void main(String[]args){// 目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景。
Z z= new Z();
Z z2= new Z( name:"播妞");
}
}
子类构造器是如何实现调用父类构造器的
- 默认情况下,子类全部构造器的第一行代码都是super()(写不写都有),它会调用父类的无参数构造器
- 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(…),指定去调用父类的有参数构造器
目标:搞清楚子类构造器为什么要调用父类构造器,有啥应用场景上
public class Test2{
public static void main(String[]args){
//1 目标:于类调用父类构造器的常见应用场景。
Teacher t= new Teacher("李四",36,"Java");
System.out.println(t.getName());
System.out.println(t.getAge());
System.out.println(t.getski11());
class People{
private string name;
private int age;
public People(){
}
public People(string name, int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
class Teacher extends People{
private string skill;
public Teacher(){
}
public Teacher(string name,int age, string skill){
super(name,age);
this.skill =skill;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
子类构造器调用父类构造器的执行原理
- 子类构造器可以通过调用父类构造器,把对象中包含父类这部分的数据先初始化赋值
- 再回来把对象里包含子类这部分的数据也进行初始化赋值。
public Teacher(string name,int age, string skill){
super(name,age);
this.skill =skill;
}
this(…)调用兄弟构造器
- 任意类的构造器中,是可以通过this(…)去调用该类的其他构造器的
public class Test {
public static void main(String[] args) {
//! 需求:如果学生没有填写学校,那么学校默认就是黑马程序员
Student s2 = new Student( name:"张三",age: 28);
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getSchoolName());
}
class Student{
private String name;
private int age;
private String schoolName;
public Student() {
}
public Student(string name, int age){
//this.name = name;
//this.age = age;
//this.schoolName = "黑马程序员";
this(name,age,schoolName:"黑马程序员"); //任意类的构造器中,是可以通过this(...)去调用该类的其他构造器的
}
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age; //this调用的就是这个类
this.schoolName = schoolName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
}
this(…)和super(…)使用时的注意事项:
- this(…)、super(…)都只能放在构造器的第一行,因此,有了this(…)就不能写super(…)了,反之亦然。
1.4 多态
1.4.1 什么是多态?
- 多态是在继承/实现情况下的一种现象,表现为:
对象多态
、行为多态
。
1.4.2 多态的具体代码体现
public class People {
public void run(){
System.out.println("人跑得很快");
}
}
public class Teacher extends People{
@Override
public void run() {
System.out.println("老师跑得很快");
}
}
public class Student extends People{
@Override
public void run() {
System.out.println("学生跑的很快");
}
}
识别技巧:编译看左边,运行看右边 就是编译的时候编译people 运行的时候按照student类运行 在student类里寻找
public class Test {
public static void main(String[] args) {
// 目标:认识多态:对象多态,行为多态。
// 1、对象多态
People P1 = new Teacher();
P1.run();//识别技巧:编译看左边,运行看右边
People P2 = new Student();
P2.run();
}
}
多态的前提
- 有
继承/实现
关系存在父类引用子类对象
存在方法重写
多态的一个注意事项
- 多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。
- 对于变量,编译看左边,运行看左边 就是看people中有什么就是执行什么
public class Test {
public static void main(String[] args) {
// 目标:认识多态:对象多态,行为多态。
// 1、对象多态
People P1 = new Teacher();
P1.run(); // 识别技巧:编译看左边,运行看右边
System.out.println(P1.name); //注意:对于变量,编译看左边,运行看左边
People P2 = new Student();
P2.run();
}
}
1.4.3 使用多态的好处
- 在多态形式下,右边对象是解耦合的,更便于扩展和维护
- =号右边随时可以把Teacher换成Student 这就是解耦合
- 如果右边写死不能随时更换,那就是紧耦合
- 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利
public class Test {
public static void main(string[] args){
// 目标:理解多态的好处
// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
People p1=new student();
p1.run();
// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
Student s =new Student();
go(s);
Teacher t = new Teacher();
go(t);
public static void go(People p){
}
多态下会产生的一个问题,怎么解决?
- 多态下不能使用子类的独有功能。
public class Teacher extends People{
@Override
public void run() {
System.out.println("老师跑得很快");
}
public void test(){
System.out.println("老师需要教知识~~~");
}
}
public class Student extends People{
@Override
public void run() {
System.out.println("学生跑的很快");
}
public void test(){
System.out.println("学生需要考试~~~");
}
}
public class Test {
public static void main(string[] args){
// 目标:理解多态的好处
// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
People p1=new student();
p1.run();
p1.test();//报错 多态下存在的问题:无法直接调用子类的独有功能。 因为编译看左边people people里面没有test
// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
Student s =new Student();
go(s);
Teacher t = new Teacher();
go(t);
public static void go(People p){
}
1.4.4 类型转换
- 自动类型转换:父类 变量名=new 子类();
- 强制类型转换:子类 变量名=(子类)父类变量
强制类型转换的一个注意事项
存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。
public class Test {
public static void main(string[] args){
// 目标:理解多态的好处
// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
People p1=new student();
p1.run();
p1.test();//报错 多态下存在的问题:无法直接调用子类的独有功能。 因为编译看左边people people里面没有test
// 强制类型转换
Student s1=(student)p1;
s1.test();
//! 强制类型转换可能存在的问题:编译阶段有继续或者实现关系就可以强制转换,但是运行时可能出现类型转换异常
Teacher t1 = (Teacher) p1; // 运行时出现了:ClassCastException
// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
Student s =new Student();
go(s);
Teacher t = new Teacher();
go(t);
public static void go(People p){
}
强转前,Java建议:
- 使用instanceof关键字,判断当前对象的真实类型,再进行强转。
p instanceof Student
public class Test {
public static void main(string[] args){
// 目标:理解多态的好处
// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
People p1=new student();
p1.run();
p1.test();//报错 多态下存在的问题:无法直接调用子类的独有功能。 因为编译看左边people people里面没有test
// 强制类型转换
Student s1=(student)p1;
s1.test();
//! 强制类型转换可能存在的问题:编译阶段有继续或者实现关系就可以强制转换,但是运行时可能出现类型转换异常
Teacher t1 = (Teacher) p1; // 运行时出现了:ClassCastException
if(p1 instanceof Student){
Student s2 = (student) p1;
s2.test();
}else {
Teacher t2 = (Teacher) p1;
t2.teach();
}
System.out.println("---------------------")
// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
Student s = new Student();
go(s);
Teachert = new Teacher();
go(t);
public static void go(People p){
p.run();
if(p instanceof student){
Students=(Student)p;
s.test();
}else if(p instanceof Teacher){
Teachert=(Teacher)p;
t.teach();
}
}
}
}