【java SE】java中的类和对象

目录

认识面向对象

类的定义和使用

类的定义

类的实例化

this引用

变量名与形参名相同起冲突

this引用的特点

构造方法

总结一下this 

static关键字(很重要!!!)

如何访问被static修饰的成员呢?

代码块

实例代码块

静态代码块

static关键字大总结:

java内部类

那如何实例化内部类呢???

内部类如何访问外部类呢???

 内部类可不可以定义static修饰的成员呢???

那外部类如何访问内部类呢??

静态内部类

 如何实例化静态内部类呢???


认识面向对象

面向对象就是:把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。对象即为人对各种具体物体抽象后的一个概念,人们每天都要接触各种各样的对象,如手机就是一个对象。Java是一门纯面向对象的语言(Object Oriented Program,继承OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好

或许看这个晦涩难懂的概念的确很抽象那我就举几个例子。

比如:洗衣服

在我们以前洗衣服的时候都要经过这10步,我们需要自己经过拿盆->放水->将衣服放进水里->放洗衣粉->手搓->换水->放洗衣粉->手搓->拧干->晾衣服。这10步都是我们洗衣服的过程,虽然我们能把衣服的污渍全部洗净,但是很消耗我们的时间并且特别的麻烦。

而我们现在洗衣服的方式

 我们只需要将衣服放进洗衣机里,然后倒入充足的水,倒入洗衣粉,把衣服放进洗衣机,等待即可,我们从中可以发现,通过洗衣机洗衣服完全不需要我们自己动手自己做,只需要自己,衣服,洗衣粉,洗衣机这四个对象就可以完成某个任务。


通过上面两种方式我们可以得出结论,传统洗衣服的方式就是依靠自己取洗衣服,消耗时间成本过多,特别的麻烦,但是效率更高。

现代洗衣服的方式只经过几个对象各自完成自己相对应的任务即可。


再举一个例子:

比如我们学完变成之后一年年薪挣了很多很多钱,我们就可以给自己换一个mac电脑;

我自己去买:打开手机->打开淘宝/京东/网购软件->搜索mac电脑->查询价格->查询型号/内存/手机颜色->咨询服务人员->确认购买->付钱->下单->取快递->拿到mac进行工作。

让朋友帮买:给朋友打电话->跟朋友说我要买mac->朋友去买->到货之后给我。


上面的例子也是如果是我自己操作就会浪费很长的时间,但如果是让朋友帮买,只需要 我,朋友,mac电脑这几个对象就可以帮我买到电脑。这也就是面向对象编程。

面向对象与面向过程的本质的区别    更加细致的细节可以去看一下这篇博客。


类的定义和使用

既然是面向对象编程,那我们肯定要有对象(面向对象具体要实现这几步  定义对象,创建对象,适使用对象完成某些功能)。

第一步:怎么定义对象呢?这也就是我们第一个要讲的类。什么是类呢?

类的定义

是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成后计算机就可以识别了

举一个例子:比如手机都会有这几个属性:颜色 ,型号 ,品牌 ,屏幕尺寸等等,手机的功能:打电话,发微信/信息,娱乐/购物/玩游戏等等功能。每个手机都会有这些属性和功能,出厂商也会根据这些属性来制造手机。所以这些由属性和方法组成的这些就像一个模板,我们就是根据这个模板来制造不同的手机(也就是对象) 在java中这个模板(这些属性和功能)就是类

那在java程序中怎么定义这个类呢?

  • 类的定义格式
// 创建类
class ClassName{
    field; // 字段(属性) 或者 成员变量
    method; // 行为 或者 成员方法
}

1):class是java中的关键字用来定义一个类 。  2):Classname是类名这里要注意使用大驼峰(每个单词首字母要大写) 。  3):field是你定义的属性,也叫作成员变量。  4):method是对象能实现的功能也叫作成员方法。

我们来定义一个手机这个类:

class SmartPhone {
    public String brand;//手机的品牌
    public String model;//手机型号
    public int measurement;//手机尺寸
    public void telephone() {//打电话的功能
        System.out.println("我要打电话!");
    }
    public void weChat() {//发微信的功能
        System.out.println("我要发微信!");
    }
}

我们来剖析一下:

 再来举一个例子:定义一个学生类:

class Student {//定义一个学生类
    //成员变量<--->属性   定义在方法的外面  类的里面
    public String name;//姓名
    public int id;//学号
    public String sex;
    public int height;//身高
    public int weight;//体重
    //成员方法----->学生能够实现的功能
    public void eat() {//
        System.out.println("我要吃饭!");
    }
    public void sleep() {
        System.out.println("我要睡觉");
    }
    public void programming() {
        System.out.println("我爱programming,我爱java!");
    }
}

 我来总结一下需要注意的点:

1):一个文件只能有一个public修饰的类,并且文件名要与类名是相同的,我们定义的类不能加public。

2):我们如果想要修改文件名可以  这样修改文件名同时类名也被自动修改。

 3):成员变量一定是定义在类的里面,方法的外面。

4):定义的类名采取大驼峰。

5):类就相当于一个模板,也就是对象拥有的属性和功能。通过类可以创建多个对象。


类的实例化

前面说有类,类就像是一个模板,但是有了模板干什么用呢?那当然是创建对象了,通过这样的模板就可以创建很多的对象。就像是一张图纸就可以建设多个高楼大厦一样。

定义了一个类,就相当于在计算机中定义了一种新的类型(java中就是把c语言的结构体替换成类,java中的类不仅有c语言结构体的功能,而且还有结构体没有的功能,相当于更新),与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:PetDog类和Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)

有了类我们怎么创建对象呢?

用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。
好我们接着上面手机的那个类来创建一个smartphone对象;

我们来画图理解一下(它在内存中是怎么存储的?)

 我们有了这个对象就可以访问这个对象的属性和方法,也就是可以给这个对象初始化属性,实现这个对象有的功能。



 刚才将了实例化对象我们来总结一下吧:

1):我们通过new关键字来创建一个对象(也叫作实例化对象),实例化对象的同时就会为对象在堆上开辟一块内存。我们通过对象的引用就可以访问到对象的属性和方法。

2):访问对象->对象的引用 . 成员变量/成员方法

3):如果不给属性/成员变量赋值的话,编译器就会自动初始化为对应的默认值。


this引用

 我们来通过一个例子来讲解this引用

变量名与形参名相同起冲突

以下我定义了一个show方法用来为手机属性初始化。

 

大家可以注意到我的形参变量名:

 如果我改成跟属性名一样呢?不是说形参名可以任意取么?

 这里答案就会出现问题,为什么是默认的值呢?我不是调用show初始化了么?

原因是我们不知道到底是谁给谁赋值,这就会造成错误。

我们加上this后


再举一个例子:

多个对象传参调用show函数

出现上述情况根部就不知道先给谁传参这就会导致冲突。


就上述两种情况我们该如何解决这个问题呢?

就是使用我们的this引用就可以很好地解决这个问题。 


 为什么使用this就可以呢?this是干什么的呢?

this代表当前对象的引用,也就是通过地址传参。

java编译器给每个“成员方法“增加了一个隐藏的引用类型参数,该引用参数指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

一般建议是习惯使用this,加上总不会出错    -————>  this.成员变量 -->记住this代表当前对象的引用。


this引用的特点

1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
2. this只能在"成员方法"中使用
3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象,具有final属性
4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收

构造方法


  • 对象是如何产生的?

对象的产生分为两步:1.为对象分配内存。2.调用合适的构造方法。

更深入的大致分为:

1.检测对象对应的类是否加载了,如果没有加载则加载
2.为对象分配内存空间
3.处理并发安全问题
比如: 多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

4. 初始化所分配的空间
即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值

我们这里先谈一谈现在我们知道的初始化有哪几种。

一种是在类里面就地初始化;例如:

 但是这里有一个缺点,难道所有的手机都是华为 这些型号么?当然不是,所以,一般不这样初始化,只有在特定的场景才可以使用这样的初始化。

另一种是在我们创建完对象时在初始化;

但是这样的初始化如果创建多次修改就会很麻烦。


最后我们就要讲一下最好用的那就是构造方法;

在回顾一下,我们一个对象生成大致为两个过程,一是为对象分配内存,二是调用合适的构造方法。

  • 那构造方法到底是干什么的呢?

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。


构造方法其实就是在对象创建之前就已经初始化完成;也就相当于人刚出生父母就会起名字。


构造方法的要求:

1):构造方法没有返回类型,void也不行,它的名字要和类名相同。

2):一个类中至少要有一个构造方法,就算在程序中没有写构造方法,编译器会为我们自动生成一个不带有参数的构造方法(原因是一个对象生成有两步,一是为对象分配内存,而是调用合适的构造方法,所以类中肯定至少要有一个构造方法)。

3):自己写的构造方法可以不带参数可以带1,2,3多个参数。但是当你自己写构造方法的时候,编译器就不会生成构造方法,只会调用你写的构造方法。


在java程序中怎么创建一个构造方法呢?

  • 不带有参数的构造方法


  • 带有参数的构造方法


这里可以发现当我们写了带有参数的构造方法,它就不会调用编译器自动生成的构造方法


我们怎样在构造方法中调用构造方法呢?

答案是利用this

 


总结一下this 

this.data——>访问成员变量

this.func()——>访问成员方法

this()——>访问本类中其他构造方法

当然在使用this在构造方法中调用另外一个构造方法的时候,只能够调用一次并且要放在第一行;

比如举个反例

  • this调用构造方法时只能在这个构造方法调用一次

  • this调用构造方法时候只能在这个构造方法的第一行调用

  • 并且this在调用构造方法的时候不能形成环


static关键字(很重要!!!)

我们都知道在类里面的,方法外面的叫做成员变量,类中还有定义的成员方法。其实成员变量分为普通成员变量(也叫实例成员变量)和静态成员变量(静态成员变量是用static修饰的成员)。当然方法也有普通成员方法和静态成员方法。


这种静态的成员变量和方法是利用关键字static所修饰的,被static修饰的成员变量和方法不属于任何对象,它是被所有对象所共享的。就像生活中老师给我们讲课一样,我们所有人都在听讲台上老师的讲课,这里老师就是被我们大家所共享的。切忌被static修饰的成员不属于任何对象,他是被所有对象共享的。


如何访问被static修饰的成员呢?

两种访问方式访问静态成员

1:类名 . 静态成员

2:对象的引用 . 静态成员

一般有两种方式访问静态成员但是我们建议用类名访问静态成员。  

因为,非静态的成员变量和成员方法依赖于对象 ,静态的成员变量不依赖于对象,既然不依赖于对象那在静态方法里就不能使用this,super关键字,因为他们与对象有关依赖于对象。


那被static修饰的成员既然被对象所共享,那它存放在哪里?

我们再来回忆一下JVM内存分布:有java虚拟机栈,本地方法栈,堆,方法区,程序计数器。

我们学过前面的知识都知道对象是存放在堆上的,而我们刚才说被static修饰的成员不依赖于对象,那被static修饰的成员肯定不在堆上,其实它是在方法区上的。

被static修饰的成员存放在方法区中;


这里还有一个问题为啥我们以前在做题的时候,在main函数里调用其他函数为啥都要加上staitc修饰呢?不加可不可以呢?

 答案是不可以的。所以我们就总结出一个结论:静态的成员方法只能够访问静态的不能够访问非静态的。

那非静态的方法能否访问静态的成员或者方法呢???


普通的成员方法可以访问静态的成员变量反过来静态的成员方法不能访问普通的成员变量和方法,在静态方法的内部不能使用非静态的。


静态成员的生命周期:静态成员一般随着类加载而创建,随着类卸载而消失。


代码块

代码块一般用于初始化,代码块分为实例代码块,静态代码块,本地代码块,同步代码块,构造代码块等等。我们这里主要讲解重要的实例代码块和静态代码块,构造代码块,以及优先顺序。

实例代码块

实例代码块一般是用于实例代码块的初始化

例如:

 实例代码块与构造方法的顺序:

打印结果 :

所以实例代码块优先于构造方法先执行。 

但为什么呢?

从字节码的角度看,编译器是把实例代码块的代码拷贝到构造方法之前编译。


静态代码块

静态代码块是用于给静态成员初始化的;

比如:


那它的顺序又会是怎么样的呢???

打印结果:


得出一个结论:执行顺序是  静态代码块优先于实例代码块优先于构造方法执行。 


那我创建两个静态代码块又会是是怎样呢?

 打印结果;

虽然都会执行,但是只保留一份。这证明当有多个static代码块时会根据优先顺序执行,初始化结果会发生覆盖,后面的覆盖前面的。

 并且还能说明一点:当没有创建对象的时候,实例代码块和构造方法不会被执行。


静态代码块注意点:

  • 静态代码块不管生成多少个对象,其只会执行一次
  • 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
  • Java代码在经过编译器编译之后,如果要运行必须先要经过类加载子系统加载到JVM中才能运行。在加载阶段:

在链接阶段第二步准备中会给静态成员变量开辟空间,并设置为默认值,在初始化阶段,会执行静态代码块中的代码。

  • 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次合并,最终放在生成的<>方法中,该方法在类加载时调用,并且只调用一次。
  •  实例代码块只有在创建对象时才会执行

static关键字大总结:

  • 被static修饰的成员不属于任何对象,他是被所有对象共享的。
  • 建议用类名访问静态成员
  • 静态的成员变量不依赖于对象,既然不依赖于对象那在静态方法里就不能使用this,super关键字,因为他们与对象有关依赖于对象。
  • 被static修饰的成员存放在方法区中;
  • 静态的成员方法只能够访问静态的不能够访问非静态的。
  • 普通的成员方法可以访问静态的成员变量反过来静态的成员方法不能访问普通的成员变量和方法,在静态方法的内部不能使用非静态的。
  • 静态成员的生命周期:静态成员一般随着类加载而创建,随着类卸载而消失。

代码块:

  • 实例代码块优先于构造方法先执行。 从字节码的角度看,编译器是把实例代码块的代码拷贝到构造方法之前编译。
  • 代码块执行顺序是  静态代码块优先于实例代码块优先于构造方法执行。 
  • 静态代码块只保留一份。这证明当有多个static代码块时会根据优先顺序执行,初始化结果会发生覆盖,后面的覆盖前面的。
  • 当没有创建对象的时候,实例代码块和构造方法不会被执行。
  • 静态代码块不管生成多少个对象,其只会执行一次
  • 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
  • 在编译代码时,编译器会按照定义的先后次序依次合并,最终放在生成的<>方法中,该方法在类加载时调用,并且只调用一次。
  •  实例代码块只有在创建对象时才会执行

java内部类

在java中我们把一个类定义在内部,定义再内部的类叫做内部类,定义再外部的叫做外部类。

比如:

//外部类
class OutClass4 {
    public int data1;
    public double data2;
    public int data3;
    //内部类
    class InnerClass4{
        public int data4;
        public double data5;
        public int data6;
    }
}

我们如何实例化内部类呢????

首先我们之前学过实例化外部类我们来回忆一下。

 
  • 那如何实例化内部类呢???

首先内部类是在外部类的里面,所以内部类也是外部类的一个成员,我们可以理解为内部类与外部类成员是同等级别的 。

我们有两种实例化内部类方式:

第一种:

OutClass outclass = new OutClass();
//创建内部类对象   这里的内部类相当于外部类的一个成员与外部类的成员是同一个等级的
//外部类.内部类 变量名 = 外部类对象的引用. new 内部类对象
OutClass.InnerClass innerClass = outclass.new InnerClass();

 首先内部类是外部类的一个成员我们得先实例化外部类对象,然后通过外部类.内部类进行访问到内部类,又因为内部类也是类,所以也要使用new关键字实例。

第二种:

OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();

这种实例化方式就是一步到位同时实例化外部类和内部类,然后外部类.内部类访问到内部类。

内部类如何访问外部类呢???

在内部类中直接就可以外部类成员。

如果内部类和外部类成员重名了会怎么办呢??

 答案是优先访问内部类,这就符合就近原则,方法定义在哪个类的内部就会先访问谁。

 如果非要访问外部类的成员呢?

我们可以利用外部类类名.this.外部成员就可以访问到外部成员。


 内部类可不可以定义static修饰的成员呢???

 答案是不可以的。

 如果非要定义static修饰的成员呢???

 那我们必须用final修饰,因为被final修饰的在编译器编译的时候就已经有值了。

 同样内部类也不能定义静态的方法。


那外部类如何访问内部类呢??

如果我们要在外部类中访问内部类中的成员需要创建一个内部类对象,然后通过内部类对象的引用进行访问。

所有代码:

class OutClass {
    public int ret = 9999;
    public String data1 = "厚积薄发1";
    public int data2 = 10;
    public double data3 = 0.5;
    public static int count = 15;
    public void eat() {
        System.out.println("我要吃饭!!!");
    }
    public void sleep() {
        System.out.println("我要睡觉!!!");
    }
    class InnerClass {
        public int ret = 9;
        public String data4 ="厚积薄发2";
        public int data5 = 520;
        public double data6 = 13.14;
        //当内部类成员和外部类成员重名的时候
        //访问内部成员------->就近原则在哪个类的里面就访问谁
        public void methodRet1() {
            //System.out.println(ret);
            //如果想要优先访问外部类的成员我们需要外部类类名.this.外部类成员
           System.out.println(OutClass.this.ret);
        }
        public void method7() {
            //内部类直接可以访问外部类成员
            System.out.println(data1);
            System.out.println(data2);
            System.out.println(data3);
            System.out.println(data4);
            System.out.println(data5);
            System.out.println(data6);
            System.out.println(count);
        }

    }
    public void method1() {
        //外部类访问内部类的成员需要先创建内部类的对象
        InnerClass innerclass = new InnerClass();
        System.out.println(innerclass.data4);
        System.out.println(innerclass.data5);
        System.out.println(innerclass.data6);
        //System.out.println(innerclass.count1);
    }

    public void methodRet2() {
        System.out.println(ret);
    }
}

public class TestDemo {
    public static void main(String[] args) {
        //如何访问内部类成员
        //首先先要创建外部类的对象
        OutClass outclass = new OutClass();
        //创建内部类对象   这里的内部类相当于外部类的一个成员与外部类的成员是同一个等级的
        //外部类.内部类 变量名 = 外部类对象的引用. new 内部类对象
        OutClass.InnerClass innerClass = outclass.new InnerClass();
        //还可以一步到位
        OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();
        innerClass.method7();
        System.out.println("=============================");
        outclass.method1();
        System.out.println("=============================");
        innerClass.methodRet1();
        System.out.println("=============================");
        outclass.methodRet2();

    }
}

静态内部类

什么是静态内部类呢?

就是定义在类的内部的类并且用static修饰的类叫做静态内部类。

 如何实例化静态内部类呢???

 与实例成员内部类的区别是这个内部类利用static修饰所以不易腊鱼对象我们只需要实例化外部类然后访问外部类就可以了


如何在内部类访问外部类成员呢???

与成员内部类不同,静态内部类不能直接访问到外部非静态成员,但是可以直接访问到静态成员。

那如何访问到非静态成员呢?

 答案是通过实例化外部类的对象,然后访问非静态成员。


如何在外部类中访问静态内部类的对象呢??

通过实例化内部类,然后通过内部类对象的引用访问内部类对象


内部类大总结:

实例内部类:

外部类.内部类 变量名 = 外部类对象的引用. new 内部类对象

实例内部类定义static修饰大的成员变量必须要被final修饰,因为被final修饰的值在编译器编译的时候就已经确认值了。

实例内部类可以直接访问外部类成员。

如果出现外部类与内部类重名的时候,在内部访问就优先访问内部的,在外部访问就优先访问外部的,采取就近原则,如果在内部类中想优先访问外部类中的成员就可以使用外部类类名.this.外部成员。

在外部类中想要访问为内部类,必须实例化内部类对象,通过内部类对象的引用来访问内部类成员。

静态内部类:

实例化静态内部类对象:外部类类名 . 内部类类名  变量名 = new 外部类类名 . 内部类类名();(此时注意静态内部类不依赖于对象,所以内部类不需要实例化内部类对象)。

在静态内部类中访问外部类成员只能访问外部类静态成员,访问非静态成员需要实例化外部类对象,通过外部类对象的引用访问外部类成员。

在外部类中访问静态内部类成员,需要实例化内部类对象通过内部类对象的引用访问内部类成员。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值