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的地址,地址不变,地址的内容发生了改变,底层因为指针修改,因为引用指向原对象在内存中的区域,所以可以修改原对象的值
}
}
//定义了一个Person类,有一个属性:name
class Person{
String name;
}
- 优化代码
- 原因是因为前面的那个代码按照视频来着的,后面自己写了下,发现用了两个类不太好理解,因此有下面的仅用一个类可能比较好理解值传递的这个内容
public class Test {
String name;
public static void main(String[] args) {
Test test = new Test();
System.out.println(test.name);
change(test);
System.out.println(test.name);
}
public static void change(Test test) {
test.name = "fenfen";
}
/*输出结果如下:
null
fenfen
*/
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;
//打印后的xiaoming的方法,发现赋值的名字在里面了
xiaoming.study();
//打印赋值后的对象属性:未赋值出来是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.2.3 整段代码理解
public class Studenta {
String name;
int age;
public void study(){
System.out.println(this.name+"学习");
}
}
class Application{
public static void main(String[] args) {
Studenta xiaoming = new Studenta();
xiaoming.name = "小明";
/xiaoming.study();
//走无参构造器
Person person = new Person();
System.out.println(person.name);
//走有参构造器
Person persona = new Person("yeuyue","女");
}
}
class Person{
String name;
String sex;
public Person() {
this.name = "手写显性构造器实例化初始值";
}
public Person(String name, String sex) {
this.name = name;
this.sex = sex;
}
}
2.3 创建对象内存分析:com.fenfen.oop.Demo3
栈的概念是弹压,就像子弹壳装弹,一粒一粒压进去,但是打出来的时候是从上面打出来的,最先压进去的最后弹出来,如果进去顺序是123,打出来顺序是321,这就是后进先出
队列的概念就是我们平时排队,按次序来,你排在第1个,那你就第一个轮到,就是先进先出,先到先来
资料补充1:https://blog.csdn.net/qwe0754444/article/details/54926707?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-3-54926707-blog-113713085.pc_relevant_multi_platform_featuressortv2dupreplace&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-3-54926707-blog-113713085.pc_relevant_multi_platform_featuressortv2dupreplace&utm_relevant_index=6
资料补充2 :https://blog.csdn.net/weixin_44688301/article/details/115632482?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-6-115632482-blog-54926707.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-6-115632482-blog-54926707.pc_relevant_default&utm_relevant_index=6
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();
}