搜 索

Java学习的自我修养(2)——OOP上半部分

  • 490阅读
  • 2022年03月14日
  • 0评论

oop上半部分:

(希望同学们在下面的课程里充满想象力,我会用生活的例子教你们)

(1)问题的提出:
想像一下你的邻居养了条狗,这狗可能是条藏獒,是条柴犬、土狗无所谓。这个老太婆知道你学过C语言,叫你用程序记录下来。

想像一个老大妈的狗需要你编写一个程序记录这条狗的生活(吃、喝、拉、撒)。如果现在是你,你现在拿C语言怎么写?需求是必须要有这条狗的名字,种类。比如这条狗叫Tom,这狗品种叫藏獒,年龄两岁。其实感觉就是一张表格,就好比给狗填一张表格。那就用C语言伪代码写一下。

#include<stdio.h>

void eat(){
    printf("Tom在吃饭.....");
}

void sleep()
{
    printf("趴着睡,躺着睡");
}
//生病啊,啥的
int main(void)
{
    char *name =Tom;
    int age =2;
    char *variety ="藏獒";
    return 0;
}

还有很多的东西,然后这个老太婆觉得你这个系统很不错,决定包养你,偶不然后她给你钱了。你发现这是商机啊!你就去问王大爷这套系统要不要,王大爷说今后你就是他的得力干将。然后你打开笔记本发现又要再写一个程序,你又稀里糊涂写了一个程序。你就写了两个程序。那这个问题有什么方法解决吗?
(2)烦人:
你可能想到了,用函数传参。

#include<stdio.h>
char *name;
int age;
char *variety;
void eat(){
    printf("Tom在吃饭.....");
}

void sleep()
{
    printf("趴着睡,躺着睡");
}
//生病啊,啥的
int main(void)
{
    dog("Tom",2,"藏獒”);
      dog("Jerry",2,"拉布拉多”;
    eat();
    sleep();
    return 0;
}
void dog(char *n,int a,char *v){
    *name =n;
    age =a;
    *variety =v;
}

你会发现这种方案好烦, 传参啥的,然后张大爷把你的传奇故事给你小区的大爷大妈说了,假如有100多号人你怎么写?即便用结构体,传参太烦人了,你该怎么办呢?从main函数自上到下依次执行,100多个人找你写程序,会不会觉得烦人。

(2)变换思维

你发现没有我们现在的思维是这狗的名字,这狗的品种,这狗吃饭,这狗睡觉,感觉就像一条直线,先干嘛,再干嘛。全程都有一个词过程
1、过程

1)思考一些过程,

2)思考第一步怎么做

3)思考第二步怎么做

4)接着怎么做

5.....

6)最后怎么做(return 0);

这狗的名字就定义一个字符串,这狗吃饭就定义一个函数。想到的时候再去做,当你饿的时候才想到翻冰箱,当你想睡觉的时候,才上床盖被子睡觉。

你想去做什么的时候去做了,然后去做了,这就是过程。

那现在我们改变一下思维,我们不能把张大爷的狗每天吃饭的过程都写一遍,也不可能把老太婆每天的经历写一遍。两条狗的过程是不一样的。所以我们不能用过程去写。

走一步看一步:没有目标没有理想的咸鱼。

基于过程缺点:目标不明确,不适用大众(你朋友走一步看一步,可能在打工,你走一步看一步,可能就在要饭)。

所以这个程序要完成这些目标:

1、该程序,要大众化。(你的狗有名字,我的狗应该也有名字)

2、目标。(有了目标,就知道你下一步就能干啥)(给100多条狗写程序)

3、不强调过程。(不惜一切代价,什么事都能干)(不强调狗怎么睡觉)

目的:记录下这条狗24小时干的事,我们干事强调目标,不强调过程。

pop:面向过程(C语言)(目标不明确)(追踪目标太复杂)

oop:面向对象(对象就是目标)(张大爷家的狗24小时做的事)

(3)规划明确目标站在更高层次解决问题

明确目标:比如你要考研,

规划、计划:你要设计它,第一个月要学啥,第二个月要学啥。当你把这些计划、规划执行完的时候,

就完成了目标。

那现在设计狗的系统,你也要设计好,你不可能一个个问你的邻居,说白了面向对象编程,就是在更高的层次看待事物:这狗可能越来越多,大爷大妈可能越来越多,你还需要关心这狗几点睡觉,几点吃饭。而应该是用户去记录他的狗几点吃饭,几点睡觉。那你就站在更高的层次看待事物了。

(4)上代码,设计体验面向对象编程,实例和对象
设计思维:

去考虑

先考虑共性。(名字、类别、年龄)

所有的狗都会的东西

公共的特性谁家的狗都这样,设计完成,目标完成

idea快捷键:shift+f6改名,alt+insert:快速创建

package com.xxxx.bean
    public class Dogs{
        //故意没写main方法,所有的狗都有名字,都有类别,都有年龄。
     public   String name;
     public    String variety;
     public    int age;
        //所有的狗都会睡
        void eat(){
            System.out.println(name+"狗吃了啥");
            System.out.println(this.name+"狗吃了啥");
            
        }
        void sleep(){
            System.out.println(name+"狗睡觉");
        }
        void sick(){
            System.out.println("狗生病");
        }
    }
//谁家的狗都满足上述目标,所有目标完成,设计也完成。

那现在这个项目写完了,再写一个类表示程序运行。

public class Application{
         public static void main(String[] args){
            //张大爷!你可以试试了!这个App,先注册
            Dogs zhangDog= new Dogs();
            zhangDog.name ="Tom";
            zhangDog.age =2;
            zhangDog.variety="藏獒";
         // 张大爷的狗睡觉了
            zhangDog.sleep();
            
          //王阿姨你也可以试试了,先注册
            Dogs wangDog =new Dogs();
            //发现没就分开了
            wangDog.name= "Jerry";
            wangDog.age =3;
            wangDog.variety="拉布拉多";
        }   
}

从目标的角度去区分,这条狗所有的信息都归这个账号管,zhangDog是目标,wangDog也是目标,可操作的东西还是目标这东西叫啥:

我们有一个专业的名词叫做对象——或者叫实例。你想一下狗原本是抽象的,天下这么多的狗,我们创建了一个实例张大爷家的狗。

那对象和实例有什么区别?对象其实大于实例,实例:现实的一个东西对抽象的东西进行表达,是一个活生生存在的事物,它是唯一的。

一个活生生的事物对抽象的事物进行表达,那别人问你什么是狗,你一指张大爷家的狗就是。所以你可以叫对象也可以叫实例。

我们一直操作这个实例,这个对象。

那现在面向对象编程理解了吗?

(4)去你md成员变量行为类和this
​ 类当中的变量和方法都总称为属性:共性和特性。

​ 成员变量:它们组成和构成了类。(也属于属性)。

​ 它们是类的组成部分。

​ 一个动作,这些方法(函数)在类当中,我们有个 很好的名字——行为。

​ zhangDog.name:对象的属性。

​ this:指调用对象。

package com.xxxx.bean
   //狗类 都具有这些属性(共性、特性)
    //类当中的变量和方法都总称为属性(共性、特性)
    // 假如现在李阿姨家的狗是二哈,会发疯。(这是特性)
    
    public class Dogs{
    //这些变量定义为成员,(成员的定义:社会团体、社会组织和家庭的组成成员)
    //成员变量:他们组成和构成了类,所以我们这样命名
     // 他们是类的组成部分,宠物狗没有这些就不能称为宠物狗
        public   String name;
    public    String variety;
    public    int age;
      //一个动作,这些函数(方法)在类当中,我们有一个很好听的名字————行为
        void eat(){
            System.out.println(name+"狗吃了啥");
            System.out.println(this.name+"狗吃了啥");
            //所以this就指代这个对象zhangDog
        }
        void sleep(){
            System.out.println(name+"狗睡觉");
        }
        void sick(){
            System.out.println("狗生病");
        }
    }
public class Application{
         public static void main(String[] args){
            //张大爷!你可以试试了!这个App,先注册
            Dogs zhangDog= new Dogs();
            zhangDog.name ="Tom";
            zhangDog.age =2;
            zhangDog.variety="藏獒";
         // 张大爷的狗睡觉了
            zhangDog.sleep();
            
          //王阿姨你也可以试试了,先注册
            Dogs wangDog =new Dogs();
            //发现没就分开了
            wangDog.name= "Jerry";
            wangDog.age =3;
            wangDog.variety="拉布拉多";
        }   
}

(5)注销账户和空指针异常
张大爷突然觉得你这个系统不好用,那你只能让他注销吧

//账户注销吧
zhangDog = null;
//然后你再输入
System.out.println("zhangdog "= +zhangDog.name);

出现NullPointerException:空指针异常。

说明对象出现问题。那这系统里就不会有zhangDog的属性了。

(6)oop封装:
为什么张大爷觉得你的系统不好用呢?

肯定是你系统做的有问题。

张大爷说你系统不安全,说王阿姨就能把你家狗信息改掉。

比如 zhangDog.age =-100;张大爷多按了一个符号,那怎么办呢?加个if?那就不符合面向对象了。

package com.xxxx.bean
    public class Dogs{
        // 那我改成private
  private   String name;
  private    String variety;
  private    int age;
       
        void eat(){
            System.out.println(name+"狗吃了啥");
            System.out.println(this.name+"狗吃了啥");
            
        }
        void sleep(){
            System.out.println(name+"狗睡觉");
        }
        void sick(){
            System.out.println("狗生病");
        }
    }
public class Application{
         public static void main(String[] args){
            Dogs zhangDog= new Dogs();
            //比如我现在把名字改为,用户不能为所欲为(public就会造成)。所以我们改为private
            zhangDog.name ="草泥马";
            zhangDog.age =2;
            zhangDog.variety="藏獒";
            zhangDog.sleep();
            Dogs wangDog =new Dogs();
            wangDog.name= "Jerry";
            wangDog.age =3;
            wangDog.variety="拉布拉多";
        }   
}

我们把成员变量做的安全,使用private代替public成员变量的特性,我们另外提供getter and setter,这种方法叫做OOP-------封装。

比如:zhangDog=-100;

public:公共的,公有的——用户可以为所欲为。

private:私有的,用户不可以为所欲为。

我们要给用户一个能设置的,能获取的,但不能瞎搞的:

private int age;

public void setAge(int age){
        if(age<0||age>100){
            this.age=0;
        }
        else{
            this.age=age;    
        }
}
//就能得到年龄。
public class Application{
         public static void main(String[] args){
            Dogs zhangDog= new Dogs();
            zhangDog.setAge(20);
               System.out.println(zhangDog.getAge());    
        }   
}

所以我们用getter、setter方法和private一起用。

我们用alt+insert,选择geter和setter自动生成。

(7)引入jar包lombok(自动生成getter、setter)
在setting里找到plugins,搜索lombok,如果找不到请使用科学上网。

@Getter
@Setter

爆红了对吧!去引入jar包。

maven repository:下载jar包,在idea下新建jar文件夹,拖进去,add as library。就导入了

如果还爆红了,出现问题,去看setting里的build中,找到Annotation Processors,设置Enable annotation processing。去build里rebuild project就可以使用了。如果还有问题去GitHub官网。

特殊的单写就可以了————方法的重写。

(8)To__string:自己玩(我现在输出一个对象和我不加toString输出一个对象的区别)
你用工具可以,但是getter,setter方法自己一定要会写。

lombok@Tostring;

@Tostring
System.out.println("zhangDog"+zhangDog);

(9)构造方法:

public class Application{
         public static void main(String[] args){
            //张大爷!你可以试试了!这个App,先注册
            Dogs zhangDog= new Dogs();
            //狗的信息的设置
            zhangDog.name ="Tom";
            zhangDog.age =2;
            zhangDog.variety="藏獒";
        }   
}

但是实际应该就该初始化一些信息

初始化(定义加使用)

//初始化
int[] arr={0,1,2,3}
//先定义
int[] arr=new int[4];
arr[0]=1;

构造方法不要加类型:

//有参构造器
//alt +insert Constructor
public dogs(String name,Steing variety,int age,String food){
    this.name=name;
    this.variety=variety;
    this.age=age;
    this.food=food;
}

构造器的作用是为了初始化。

(10)构造方法的重载和再探this
this指对象。

//这不就是重载吗?
//重载函数名相同,变量名不同
public dogs(String name,Steing variety){
    this.name=name;
    this.variety=variety;
}

(11)垃圾回收机制:
比如:账号注销了:zhangdog=null;

其实并没有把它释放掉。

手动垃圾回收:system.gc();就能进行垃圾回收。

它其实是可以自动垃圾回收。

(12)静态变量和静态方法:建立在类上了,在变量名(或方法名前)加static。
程序火了,小区居委会找你,现在有100多个用户,你要有个标志确定这100多个人是这个小区的。小区名叫NanGua。

静态方法和静态变量:我可以用类名直接去用。

public class Dogs{
   public static String plot ="NanGua";
}
//重点在static
public class Application{
         public static void main(String[] args){
                 System.out.println("NanGua"+Dogs.plot);          
        }   
}
//整个小区的狗都是NanGua小区的。

那如果我们整个小区的狗都要打针,整个小区的狗都要来。公开的,不是张大爷的特权,使用了static,我们使用了类名。

public class Dogs{

public static void injection(){
    System.out.println("所有的狗都要打针")
}
}
public class Application{
         public static void main(String[] args){
                 Dogs.injection();      
        }   
}

(13)private static:

public class Dogs{
   public static String plot ="NanGua";
}

使用public,可能有个安全问题,假如有个黑客,他改你代码

public class Application{
         public static void main(String[] args){
               Dogs.plot="Hack...";
        }   
}

于是:

public class Dogs{
   private static String plot ="NanGua";
   public static String getPlotInstance(){
       return plot;
   }
}
public class Application{
         public static void main(String[] args){
               System.out.println("    "+Dogs.getPlotInstance());
        }   
}

这样就只能获取了。

(14)内部类扯淡总结:
实际开发过程中,内部类并不常用。

public class Earth{
        class Sun{
        
        }
}

不推荐用内部类,除非为匿名内部类。

(15)static 单例模式 (单例设计模式,面试题)
static是建立在类上,你不可能建立在对象上,你不可能小区名还要问张大爷。更合理的是直接在程序里输出,而好处就是在这。

我们新建一个类sun。

public class Earth{
            
}
public class Application{
         public static void main(String[] args){
               Earth earth1 = new Earth();
               Earth earth2 = new Earth();
        }   
}
//发现了吗?是不是不合理了,地球只有一个

static就能解决这个问题

public class Earth{
          private  static Earth instance =new Earth();
         
    public Earth(){
        
    }
             
    public static Earth getInstance(){
        return instance;
    }
    
}
public class Application{
         public static void main(String[] args){
              Earth earthInstance = Earth.getInstance();
        }   
}

(16)OOP上半部分就结束了:

欢迎提问,但是提问之前请看《提问的智慧》。

我觉得这些文章的生动性,应该能把面向过程的思维引向面向对象。

无标签
打 赏
评论区
暂无评论
avatar