JavaSE-07 Opp面向对象(完整版)
JavaSE-07 Opp 面向对象(完整版)
1.方法的调用补充:package com.fenfen.oop.Demo1
1.1非静态方法下方法调用(不同的类)
①在Student的类中建立study的方法 package com.fenfen.oop.Demo1; //学生类的方法 public class Student { //方法 public void study(){ System.out.println("学生在学习"); } } ②在Demo2类中调用Student类中的student方法 //在别的类中调用 package com.fenfen.oop.Demo1; public class Demo2 { public static void main(String[] args) { //在方法非静态下:实例化这个类 //对象类型 对象名 = 对象值 Student student = new Student(); student.say(); } }
1.2非静态方法下的方法调用(同个类)
public class Demo2 { //static和类(class:Demo2)一起加载 public static void a(){ b();//会报错原因:可以理解为:存在的去调用不存在的了 } //没有static:这个得等到类实例化(new 后)才存在 public void b(){ a(); } }
1.3 值传递:
//值传递 public class Demo4 { public static void main(String[] args) { int a = 1; change(a); System.out.println(a);//输出仍然是a = 1 } //无返回值 public static void change(int a){ //原因:a只是一个形式参数,a=10后没有返回值给到a,于是回到了主方法,主方法中有int a = 1,因此输出就是1了 a = 10; } /* 更加高端的解释: ①change方法调用完毕就出栈了,main方法还在栈中 ②对于基本数据类型来说,给形参传递的是实参值的副本 而对于引用数据类型来说,传递则是地址的副本,但由于地址的副本和原来的相似,因此传递过去后的形参也指向同一个内存空间 */
1.4 引用传递:
public class Demo5 { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name);//null change(person); System.out.println(person.name);//fenfen } //写个方法 public static void change(Person person){ person.name = "fenfen";//原因:引用传递:指针修改,因为引用指向原对象在内存中的区域,所以可以修改原对象的值 } } //定义了一个Person类,有一个属性:name class Person{ String name; }
2. 对象的创建与分析:com.fenfen.oop.Demo2
2.1 类和方法的创建:Student,Application
//学生类 public class Student { //①属性:字段 String name;//未赋任何值,默认初始化为null int age;//为赋任何值,初始化为0 //②方法 public void study(){ System.out.println(this.name+"学生在学习");//this表示当前这个类 } }
public class Application { public static void main(String[] args) { //实例化:student对象就是一个Student类的具体实例 Student student = new Student(); Student xiaoming = new Student(); Student xiaohong = new Student(); //给对象赋值: xiaoming.name = "小明"; xiaoming.age = 3; //打印赋值后的对象属性:未赋值出来是null和0 Person person = new Person(); System.out.println(person.name); } }
2.2 构造器详解
2.2.1 无参构造器
public class Person { String name; //1、一个类即使什么都不写,也会存在构造方法(和类名相同,且无返回值),即构造器:无参构造器 //构造器的作用:实例化初始值:使用new对象,本质是在调用构造器 public Person(){ this.name = "fenfen"; }
public class Application { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name);//fenfen }
2.2.2 有参构造器
public class Person { String name; //2、有参构造器:一旦定义了有参构造,无参就必须显示定义(就是有了有参,无参不能删,空着就好) public Person(){ } public Person(String name){ this.name = name; }
public class Application { public static void main(String[] args) { //实例化了一个对象:走的无参构造器 Person person = new Person(); System.out.println(person.name); //走有参构造器 Person person1 = new Person("fenfen"); System.out.println(person1.name); } } //注:快捷键alt+insert然后点击constructor,可以选择无参或有参快速生成构造器
2.3 创建对象内存分析:com.fenfen.oop.Demo3
栈的概念是弹压,就像子弹壳装弹,一粒一粒压进去,但是打出来的时候是从上面打出来的,最先压进去的最后弹出来,如果进去顺序是123,打出来顺序是321,这就是后进先出
队列的概念就是我们平时排队,按次序来,你排在第1个,那你就第一个轮到,就是先进先出,先到先来
2.3.1 对应代码
public class Pet { public String name; public int age; public void shout(){ System.out.println("叫了一声"); }
public class Application { public static void main(String[] args) { Pet dog = new Pet(); dog.name = "馒头"; dog.age =1; dog.shout(); System.out.println(dog.name); System.out.println(dog.age); } }
2.3.2 对应内存顺序图:
3. 三大特性
3.1 封装:com.fenfen.oop.Demo4
3.1.1 相关概念:
原因: |
---|
a.程序设计应”高内聚,低耦合“,即类的内部数据操作细节不允许外界干涉,以及仅暴露少量方法给外部使用 |
b.封装:应禁止直接访问一个对象中数据的实际显示,通过操作接口去访问,以便信息隐藏 |
3.1.2 封装
//封装:属性私有 get/set public class Student2 { //名字、姓名、学号:一般封装对于属性来说比较多,对于方法少一些 //学习、睡觉 private String name; private int id; private char sex; private int age; //提供一些可以操作的这个属性的方法:因为上面private了 //提供一些public的get、set的方法 //①get获得这个数据 public String getName() { return this.name; } //②set 给这个数据设置值 public void setName(String name){ this.name = name; } //注:快捷键alt+insert然后点击setter and getter,可以快速生成 //③甚至可以在set里面写if判断来进行安全性检查 public void setAge(int age) { if (age>120 || age<0) { this.age = 3; }else{ this.age = age; } } }
public class Application { public static void main(String[] args) { Student2 s1 = new Student2(); //s1.name = "fenfen";私有的不可调用 String name = s1.getName();//get s1.setName("fenfen"); System.out.println(s1.getName());//s1.getName().sout s1.setAge(999); System.out.println(s1.getAge()); } }
3.1.3 封装的意义:
封装的意义: 1、提高程序的安全性,保护数据 2、隐藏代码的实现细节 3、统一接口 4、提高系统的可维护性 5、封装和重载一般一起用的比较多
3.2 继承:com.fenfen.oop.Demo5
3.2.1 子类继承父类的方法与属性
public class Person { public int money = 10_0000_0000; public void say(){ System.out.println("说了一句话"); } }
public class Student extends Person{ public static void main(String[] args) { Student student = new Student(); student.say(); System.out.println(student.money); }//子类继承父类,就会拥有父类的方法
3.2.2 子类继承父类私有的属性
public class Person { private int money2 = 99999999; //get和set方法针对private搞个封装 public int getMoney2() { return money2; } public void setMoney2(int money2) { this.money2 = money2; } }
public class Student extends Person{ public static void main(String[] args) { Student student = new Student(); //针对private的封装方法的调用 student.setMoney2(99); System.out.println(student.getMoney2()); } } //注: //ctrl+h可以弹出继承树
3.2.3 super详解
- super在属性上的运用
- 父类
public class Person { //protected protected String name = "fenfen父类"; }
- 子类
public class Student extends Person{ private String name = "fenfen子类"; public void test(String name){ System.out.println(name);//main传递过来的参数 System.out.println(this.name); System.out.println(super.name);//super去调用父类的 } }
- Application类
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); student1.test("fenfenmain类"); } }
- super在方法上的运用
- 父类
public class Person { public void print(){//如果是私有的方法,子类就不能直接访问了 System.out.println("Person"); } }
- 子类
public class Student extends Person{ public void print(){ System.out.println("Student"); } public void test1(){ print();//当前方法 this.print();//当前方法 super.print();//父类的方法 } }
- Application类
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); student1.test1(); } }
- super在无参构造器上的运用
- 父类
public class Person { public Person(){ System.out.println("Person无参执行了"); } protected String name = "fenfen父类"; }
- 子类
public class Student extends Person{ public Student() { //隐藏代码:调用了父类的无参构造 //即有一行:super();且调用父类的构造器必须在子类的第一行 System.out.println("子类的无参执行了"); } private String name = "fenfen子类"; }
- Application类:
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); } } /* Person无参执行了 子类的无参执行了 */
- super在有参构造器上的运用
- 父类
public class Person { //整一个有参构造器 public Person(String name){ System.out.println("Person无参执行了"); } }
- 子类
public class Student extends Person{ public Student() { super(name:"name");//记得写参数,才会去调用有参的 System.out.println("子类的无参执行了"); } private String name = "fenfen子类"; }
- Application类:
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); } }
3.2.4 方法的重写:com.fenfen.oop.Demo5
- 提前介绍多态:有static
- 父类
public class B { public static void test(){ System.out.println("B=>test"); } }
- 子类
public class A extends B { public static void test(){ System.out.println("A=>test"); } }
- Application类
public class C { public static void main(String[] args) { //方法的调用只和左边的类型有关,定义的数据类型有关 A a = new A(); a.test();//走的是A类的方法 //A继承B,父类的引用指向子类 B b = new A(); b.test();//走的B类的方法 } }
- 方法重写:非静态
- 父类
public class B { public void test(){ System.out.println("B=>test"); } }
- 子类
public class A extends B{ //重写1 @Override//把static去掉,这个就是注解:有功能的注释 public void test() { System.out.println("A=>test"); } }
- Application
public class C { public static void main(String[] args) { A a = new A(); a.test();//A=>test B b = new A(); b.test();//A=>test } }
总结看看:
/*第二次用重写的没有static的结果截然不同: 有static静态时:b调用的是B类的方法,因为b是用B类去定义的 没有static静态时:b调用的是对象的方法,b是用A类new的 重写:需要有继承关系,而且是子类重写父类 1、方法名必须相同 2、参数列表必须相同 3、修饰符:范围可以扩大: private--->default---->protected---->public 4、重写可能会抛出异常:范围可以被缩小,但不能被扩大 ClassNotFoundException 注意:子类的方法和父类必要一致:方法体不同 为啥要重写:override 1、父类的功能子类不一定需要,或者不一定满足
3.3 多态:com.fenfen.oop.Demo6
3.3.1 多态的创建
public class Main { public static void main(String[] args) { //一个对象的实际类型是确定的 //new Student(); //new Person(); //可以指向的引用类型就不确定了 Student s1 = new Student();//Student能调用的方法都是自己或者是继承来的:Student类继承了Person类 //①父类的引用指向子类的类型 Person s2 = new Student();//父类的可以指向子类,但是不能调用子类特定的方法 //②指向Object Object s3 = new Student(); } }
3.3.2 多态方法的调用
- 父类
public class Person { public void run(){ System.out.println("run"); } }
- 子类
public class Student extends Person{ //重写下父类的方法 @Override public void run() { System.out.println("son"); } public void eat(){ System.out.println("eat"); } public void go(){ System.out.println("go"); } }
- Application
public class Main { public static void main(String[] args) { Student s1 = new Student(); Person s2 = new Student(); s2.run();//子类重写了父类的方法,因此父类的方法调用的时候变成子类了 s1.run(); s1.eat(); ((Student)s2).eat();//强制转换(高类型转成) ,Person里面没有eat方法,所以强制转换成Student去调用 } }
总结一下 :
/* 多态注意事项: 1、多态是方法的多态,属性没有多态 2、父类和子类,有联系 如不符合:会出现异常ClassCastException! 3、存在条件:①继承关系②方法需要重写③父类引用指向子类对象 Father f1 = new Student(); 有些方法不能重写: ①static静态,修饰的方法,属于类,不属于实例 ②final常量,修饰的 ③private方法: */
3.3.3 instance of和类型转换
- instance of
public static void main(String[] args) { //Object > String //Object > Person > Student //Object > Person > Teacher Object student2 = new Student(); //instanceof判断左边对象是否是右边类的一个实例 System.out.println(student2 instanceof Student);//看看是不是Student类型呢true System.out.println(student2 instanceof Person);//看看是不是Student类型呢true System.out.println(student2 instanceof Object);//看看是不是Student类型呢true System.out.println(student2 instanceof Teacher);//看看是不是Student类型呢false //因为没有new:object和Teacher System.out.println(student2 instanceof String);//看看是不是Student类型呢false } } /*总结一波: System.out.println(X instanceof Y);能不能编译通过取决于X、Y有没有父子关系 */
- 类型转换
- 父类
public class Person { public void run(){ System.out.println("run"); } }
- 子类
public class Student extends Person{ public void go(){ System.out.println("go"); } }
- Application类
public class Main3 { public static void main(String[] args) { //父类 子类 //高 低 Person student = new Student(); //student.go();报错原因:student属于Person,Person中没有go //student将这个对象转换未Student类型,我们就可以使用Student类型的方法了:高往低走 Student student1 = (Student) student;//(Student)student; student1.go(); ((Student)student).go();//前面写成一句话完成类型转换 //低 高 //子类转换为父类,可能回丢失原来自己的方法 Student student2 = new Student(); student2.go(); //把student变成person类型 Person person = student2; //person.go();就用不了了 } }
3.3.4 static关键字详解:com.fenfen.oop.Demo7
- static在属性上的使用
public class Student { //静态属性 private static int age;//静态的变量 private double score;//非静态变量
public static void main(String[] args) { student student = new Student(); //用对象输出 System.out.println(student.score);//student.score.sout //用类输出 System.out.println(Student.age); //System.out.println(Student.score);没有static这个就不行 //或者直接输出 System.out.println(age+"kkkkk"); } }
- static在方法上的使用
public class Student { //静态方法 public void run(){ } public static void go(){ }
public static void main(String[] args) { Student student = new Student(); //方法调用 //用对象调 student.run(); student.go(); //用类调 Student.go(); //Student.run();没有static这个就不行:具体原因,现在是静态方法,只能去调静态方法的 //直接调 go(); } }
- static在代码块、构造器上的运用
public class Person { //代码块 { System.out.println("匿名代码块儿,一般会根据对象每次都跑,所以会被用来赋予初始值"); } //静态代码块 static { System.out.println("静态代码块儿,这个反而执行的时候是最先的,而且我就跑一次,后面不玩了"); } //构造器 public Person() { System.out.println("构造方法"); } public static void main(String[] args) { Person person1 = new Person(); System.out.println("==============="); Person person2 = new Person(); } }
- static在静态导入包的使用
package com.fenfen.oop.Demo7; //静态导入包的方法和常量 import static java.lang.Math.random; import static java.lang.Math.PI; public class Test { public static void main(String[] args) { //System.out.println(Math.random()); 不想怎么写可以在前面直接导包,但是记得写static System.out.println(random()); }
4. 抽象类和接口:com.fenfen.oop.Demo8
4.1 抽象类
4.1.1 抽象对象和方法的建立
public abstract class Action { //约束 //abstrct ,抽象方法,只有方法名字,没有具体的方法内容实现,并且抽象方法跟抽象类 public abstract void doSomething(); /* 1、不能在这个抽象类new(在main中都不给new,只能靠子类去实现它(重写? 2、抽象类中可以写普通的方法 3、抽象方法必须在抽象类中 抽象的抽象:约束 抽象存在的意义: 例如游戏中,抽象出一定的内容,每创建一个角色就去继承这个抽象类,直接重写部分方法,改掉一些不必要的东西即可 */
4.1.2 无法在其他类中new一个抽象类的对象
public class Main { public static void main(String[] args) { // new Action(); 不给new } }
4.1.3重写抽象的方法
public class A extends Action{ //继承用了abstract的类会报错,必须得重写一下才可以 //抽象类得所有方法,继承了他的子类,都必须要实现他的方法 @Override public void doSomething() { } }
4.2 接口:com.fenfen.oop.Demo9
4.2.1 创建接口以及基本方法
//接口:用interface // 写简单方法,然后有一个对应实现类UserServiceimp public interface UserService { //public void run(){ 此处需要加上abstract不然不给写方法 //} //接口中的所有定义其实都是抽象的 public abstract的方法 public abstract void run(); void add(String name); void delete(String name); void update(String name); void query(String name); //接口中定义属性:就是一个常量,很少在接口中定义常量:默认public static final public static final int AGE = 99; } public interface TimeService { void timer(); }
4.2.2 接口对应的实现类
//一个类实现接口 implemnts 接口:可以继承多个接口 //实现了接口中的类,就需要重写接口中的方法 public class UserServiceimp implements UserService,TimeService{//可以实现多个接口,实现多继承 //右击generate:implement methods或者ctrl+i快捷键 @Override public void run() { } @Override public void add(String name) { } @Override public void delete(String name) { } @Override public void update(String name) { } @Override public void query(String name) { } @Override public void timer() { }
5 内部类:com.fenfen.oop.Demo10
5.1 类中类
5.1.1创建内中类
public class Outer { private int id = 10; public void out(){System.out.println("这是外部类的方法");} //类内部类;类中类 public class Inner{ public void in(){System.out.println("这是内部类的方法");} //获得外部类的私有属性:外部出现的id = 10 public void getID(){ System.out.println(id); } //可以在内部类Inner前加上static: // 但是会出现:静态的内部类无法访问非静态的内部属性 } }
5.1.2 实例化并调用类中类
public class Main { public static void main(String[] args) { //new Outer outer = new Outer(); //通过这个外部类来实例化内部类 Outer.Inner inner = outer.new Inner();//outer.new Inner(); inner.in(); inner.getID(); } }
5.2 局部内部类(方法中的类)
public class Outer3 { //方法中的类:叫做局部内部类 public void method(){ class Inner{ public void in(){ } } } }
5.3 匿名内部类
public class Outer4 { public static void main(String[] args) { //一般是Apple apple = new Apple(); //也可以是:没有名字初始类,不用将实例保存到变量中 new Apple().eat(); //接口重写下方法 new UserService() //实际写全是:UserService userService = new UserService() { @Override public void hello() { } }; } } class Apple{ public void eat(){ System.out.println("1"); } } //整一个接口 interface UserService{ void hello(); }
「其他文章」
- 5分钟的时间制作一个反弹球游戏
- 35岁危机?内卷成程序员代名词了…
- 在线文本实体抽取能力,助力应用解析海量文本数据
- 不买排名,不去SEO,如何做到登上谷歌搜索首页?
- HtmlParse:一款超轻量级的HTML文件解析和爬取工具
- 五款当下超火热的相亲交友APP测评
- 尽一份孝心,为家人做一个老人防摔报警系统
- 作为软件工程师,给年轻时的自己的建议(下)
- 技术分享| 浅谈调度平台设计
- 组态界面推陈出新:打造新一代再生水厂工艺二维组态系统
- 平头哥 芯事访谈 | 全志科技CTO丁然:视频、AI市场爆发,RISC-V生态需要产业一起努力
- IDEA SSM Maven实现商品管理系统(超详细SSM整合项目)
- 如何为回归测试选择测试用例?
- 前端必学——函数式编程(五)
- 40篇学完C语言——(第八篇)【指针数组以及指向指针的指针】
- 焱融看|非结构化数据场景下,数据湖到底有多香?
- 低代码开发的未来~
- Docker容器:将带UI的程序直接转为Web应用,so easy
- PHP 基于 SW-X 框架,搭建WebSocket服务器(二)
- 低代码开发的前后端联调——APICloud Studio 3 API管理工具结合数据云3.0使用教程