Java——类和对象(成员变量、方法、初始化、访问权限)

面向过程语言和面向对象语言

面向过程语言的核心是编写解决某个问题的代码块,例如C语言中的函数。代码块是程序执行时产生的一种行为,但是面向过程语言却没有为这种行为指定“主体”,即在程序运行期间,无法说明到底是谁具有这个行为,并负责执行了这个行为。例如C语言编写一个“刹车”函数,却无法说明到底是“谁”具有这样的行为(就好像说话没有主语:刹车了)。也就是说面向过程语言缺少了一个最本质的概念,那就是“对象。
在面向对象语言中,最核心的内容就是对象,一切围绕着对象。

面向对象编程主要体现下列三个特性:
1、封装性:将数据和对数据的操作封装在一起。
2、继承:子类继承父类的属性和行为,在此基础上,还可以添加子类独有的数据和数据上的操作。
3、多态:两种意义的多态:
一:操作名称的多态(多个操作具有相同的名字,但操作所接收的消息类型必须不同——重载)。
二:继承多态(同一操作被不同类型对象调用时可能产生不同的行为——重写)

类和对象

类的目的是抽象出一类事物共有的属性和行为。

成员变量用来表示类的属性。方法用来表示类的行为。

类体中的内容分为两部分
{
方法的定义
变量的声明
}

万物皆可归类,且根据归类的细化程度既可合并成一类,也可分离成多类。
鸟有翅膀会飞为一类,鱼有鳃会游水为一类。
将鸟细化,雄鸟一类,雌鸟一类;
将雄鸟细化… …
… …
将细胞细化… …
… …

同时万物也可归为一类~~


由类而生对象,对象就是类的实例化,显然这个对象是具备类的属性和行为的。

以对象彰显特性,方能游刃有余将世间万物置于条理之中… …

成员变量

成员变量在整个类内都有效,其有效性与它在类体中书写的先后位置无关。

实例变量与类变量(static静态变量)

class test{
float a;//实例变量
int b;
static float c;//类变量
static  int d;
test(){
  }
}

实例变量与静态变量的区别

1.不同对象的实例变量互不相同
不创建对象,类中的实例对象不会被分配内存。
分配给不同对象的实例变量占有不同的内存空间。

2.所有类共享类变量
类被加载到内存时,就分配了相应的内存。
无论创建多少个对象,分配给这些对象的这个静态变量占有相同的一处内存。static变量的值存储在方法区。
3.类变量通过类名直接访问
类.类变量

方法

构造方法

1、构造方法的名字必须与它所在的类的名字完全相同,而且没有返回值类型。

2、允许在一个类中编写若干个构造方法,但必须保证他们的参数不同。

3、使用new运算符和类的构造方法为声明的对象分配变量,即创建对象。如果类中没有构造方法,系统会调用默认的构造方法,默认的构造方法是无参的,且方法体中没有语句。

4、如果类中定义了一个或多个构造方法,那么java不提供默认的构造方法(即类中如果有构造方法是有参的,并且默认的无参构造方法没有显式表现出来,那么new对象的时候一定要传入参数
如下所示:

public class Point {
    public Point(){//将无参构造显示出来
    }
    public Point(int a,int b){
        System.out.println("有参构造");
    }
    public static void main(String[] args) {
        new Point();//调用无参构造
    }
}
public class Point {
    public Point(int a,int b){
        System.out.println("有参构造");
    }
    public static void main(String[] args) {
        //new Point();报错
        new Point(1,2);//默认的无参构造没有显式表现出来,只能调用有参构造
    }
}

总结:
1、new运算符只能和类的构造方法进行运算,运算的最后结果是一个十六进制的数,这个数据称作对象的引用,即表达式new xxx()的值是一个引用。new 运算符在计算出这个引用之前,首先给类中的成员变量分配内存空间,然后执行构造方法中的语句,这个时候,对象还没有诞生,因为还没有计算出引用。当引用计算出后,即new xxx()表达式已经有值后,对象才诞生。

public class Person {
    String name="郭超";
    String sex="男";
    int age =21;
    public  Person(){
        System.out.println("my name is 郭超");
    }
    public static void main(String[] args) {
        Person guochao = new Person();
        //对象的引用guochao拥有了new Person()所分配的成员变量
    }
}

2、对象的引用存在栈中,对象的实体(分配给对象的变量)存在堆中。

3、jvm中变量的存放位置
局部变量(方法体中)
如果是基本类型,会把值和变量名直接存储在栈;
如果是引用类型,比如String s = new String(“william”);会把其对象存储在堆,而把这个对象的引用(指针)存储在栈。

成员变量:
基本类型和引用类型的成员变量都存在堆中。
而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。

对象实质上就是各种成员变量,不包括方法,因为方法存放在方法区(方法就是一段被编译的代码,存放在方法区)

实例方法与类方法(static静态方法)

class B{
int a;
float max(float x,float y){ //实例方法
...
}
static void speak(){//静态方法
...
}
}

实例方法与静态方法的区别

1.对象调用实例方法,类名调用类方法。

2.实例方法不仅可以操作实例变量,也可以操作静态变量。

3.静态方法中不允许出现this,super,以及本类非静态的属性和方法。

4.当类的字节码文件被加载到内存时,类的实例方法不会被分配入口地址,只有该类创建对象后,类中的实例方法才分配入口地址,从而实例方法可以被类创建的任何对象调用执行。当创建第一个对象时,类中的实例方法就分配了入口地址,再次创建对象时,不再分配入口地址,也就是说,方法的入口地址被所有的对象共享,当所有的对象不存在时,方法的入口地址才被取消;而类方法在类被加载到内存时,就分配了相应的入口地址。

总结:
实例方法可以操作实例变量、方法和静态变量、方法。
静态方法只能操作静态变量和静态方法。

this关键字

this是java的一个关键字,表示某个对象,this可以出现在实例方法和构造方法中,但不可以出现在类方法中,因为类方法可以通过类名直接使用,这时,可能还没有任何对象诞生。

1、在构造方法中使用this
this关键字出现在类的构造方法中时,代表使用该构造方法所创建的对象。

2、在实例方法中使用this
实例方法只能通过对象来调用,不能通过类名调用。当this关键字出现在实例方法中时,this就代表正在调用该方法的当前对象。

3、一个实例方法调用另一个方法或者调用本类的成员变量时可以省略方法名或变量名前面的this.或类名.但当实例成员变量的名字和局部变量的名字相同时,成员变量前面的this.或类名.就不可以省略。
如下所示:

class lake{
    int x=100;
    void setX(int x){
        this.x=x;
    }   
    void setX2(int x){
        x=x;//这里的两个x都是传入的形参x本身,均为局部变量,没有给成员变量x赋值
    }
    public static void main(String[] args) {
        lake lake = new lake();
        lake.setX(200);
        System.out.println(lake.x);//200

        lake.setX2(300);
        System.out.println(lake.x);//200
    }
}

初始化

实例初始化

实例初始化过程:创建对象时,为对象进行初始化的操作
①为成员变量显式赋值
②执行非静态代码块
③执行构造器

Java编译器其实会把这三个部分的代码,合成一个叫做(【形参列表】)实例初始化方法,即编译后的.class字节码信息中,是没有构造器这个概念。

< init > (【形参列表】)实例初始化方法的代码就是由三个部分组成:
①成员变量显式赋值的代码
②非静态代码块中的代码
③构造器中的代码
其中的①和②按顺序执行,而③一定是它们当中的最后执行。
而且,有几个构造器,就会有几个实例初始化方法。那么当你创建对象的时候,调用对应的构造器时,其实执行的是对应的实例初始化方法< init>(【…】)

public class TestBlock {
    public static void main(String[] args) {
        Demo d1 = new Demo();//调用无参构造,本质上是调用<init>()实例初始化方法
        Demo d2 = new Demo("atguigu");//调用有参构造,本质上是调用<init>(形参列表)实例初始化方法
    }
}
class Demo{
    {
        System.out.println("非静态代码块1");
    }

    private String str = assign();//调用方法,来为str进行显式赋值

    public Demo(){
        System.out.println("无参构造");
    }
    public Demo(String str){
        this.str = str;
        System.out.println("有参构造");
    }

    {
        System.out.println("非静态代码块2");
    }

    public String assign(){
        System.out.println("assign方法");
        return "hello";
    }
}

在这里插入图片描述

类初始化

类初始化即执行类初始化方法:< clinit>()
类初始化方法,一个类只有一个。它也是有编译器编译生成的,由两部分代码组成:
(1)静态变量的显式赋值代码
(2)静态代码块的代码
其中(1)和(2)是按照顺序执行

特点:
(1)每一个类的静态代码块只会执行一次
(2)静态代码块在第一次使用这个类之前执行,即在类初始化时执行。

public class TestStatic2 {
    static{
        System.out.println("TestStatic2静态代码块");
    }
    public static void main(String[] args) {
        Demo d = new Demo();//现在第一次使用Demo类,用它创建一个对象时,会导致Demo类的初始化
    }
}

class MyClass{
    static{
        System.out.println("MyClass静态代码块");
    }

    public static void test(){
        System.out.println("静态方法");
    }

}
class Demo{
    static{
        System.out.println("(1)Demo的静态代码块1");
    }
    private static String info = assign();
    static{
        System.out.println(info);
        System.out.println("(2)Demo的静态代码块2");
    }
    public static String assign(){
        System.out.println(info);
        System.out.println("(3)assign()方法");
        return "hello";
    }
}

在这里插入图片描述
一个类初始化时会先检查它的父类是否初始化,如果父类没有初始化,那么会先初始化父类。因为一个类只要初始化一次。
(1)父类的初始化< clinit>()
①父类的静态变量的显式赋值
②父类的静态代码块
(2)子类的初始化< clinit>()
①父类的静态变量的显式赋值
②父类的静态代码块

public class TestClassInit {
    public static void main(String[] args) {
        Son s = new Son();
	}
}
class Father{
    private static String info = assign();
    static{
        System.out.println("(1)父类的静态代码块");
    }
    public static String assign(){
        System.out.println("(3)assign()方法");
        return "Father";
    }
}
class Son extends Father{
    private static String info = assign();
    static{
        System.out.println("(2)子类的静态代码块");
    }
    public static String assign(){
        System.out.println("(4)assign()方法");
        return "Son";
    }
}

在这里插入图片描述

类初始化与实例初始化结合

(1)先完成父类的类初始化
(2)再完成子类的类初始化
(3)父类的实例初始化方法
(4)子类的实例初始化方法

public class TestInit2 {
    public static void main(String[] args) {
        DemoZi zi1 = new DemoZi();
        System.out.println("-------------------");
        DemoZi zi2 = new DemoZi();
    }
}
class DemoFu{
    {
        System.out.println("(1)Demo的非静态代码块1");
    }
    static{
        System.out.println("(2)Demo的静态代码块1");
    }
    private static String info = assign();
    private String message = getMessage();
    static{
        System.out.println("(3)Demo的静态代码块2");
    }
    {
        System.out.println("(4)Demo的非静态代码块2");
    }
    public DemoFu(){
        System.out.println("(5)无参构造");
    }
    public static String assign(){
        System.out.println("(6)assign()方法");
        return "hello";
    }
    public String getMessage(){
        System.out.println("(7)getMessage()方法");
        return "msg";
    }
}
class DemoZi extends DemoFu{
    {
        System.out.println("(8)");
    }
    static{
        System.out.println("(9)");
    }
    private static String info = assign();
    private String message = getMessage();
    static{
        System.out.println("(10)");
    }
    {
        System.out.println("(11)");
    }
    public DemoZi(){
        System.out.println("(12)");
    }
    public static String assign(){
        System.out.println("(13)");
        return "hello";
    }
    public String getMessage(){
        System.out.println("(14)getMessage()方法");
        return "msg";
    }
}

在这里插入图片描述

区分成员变量与局部变量

1.在方法体中声明的变量和方法的参数被称作局部变量,局部变量只在方法内有效,与其声明的位置有关:从声明它的位置之后开始有效

2.如果局部变量的名字与成员变量的名字相同,那么方法就隐藏了成员变量,必须使用this关键字使用被隐藏的成员变量。

3.局部变量没有默认值,在使用局部变量之前,必须保证局部变量有具体的值。

因为局部变量只在声明的方法体中有效,所以就没有权限修饰符修饰。

class A{
    int x=10,y;
   void f(){
            int x=5;
            y=x+this.x;  //y=15
           }
   void x(){
             int m;   //m无默认值,还没有使用,编译不出错
             x=y+m;  //无法通过编译,因为要使用,必须要指定y的值
           }       
       }

访问权限

用来修饰类,以及类的成员(方法、变量)
注:protected和private不能用来修饰类
在这里插入图片描述
1、public: 所修饰的类、变量、方法,在内外包均具有访问权限;
2、protected: 这种权限是为继承而设计的,protected所修饰的成员,对所有子类是可访问的,但只对同包的类是可访问的,对外包的非子类是不可以访问;(保护子类的访问性,无论是否在同一个包
3、包访问权限(default): 只对同包的类具有访问的权限,外包的所有类都不能访问;
4、private: 私有的权限,只对本类的方法可以使用;

权限范围:public>protected>default>private

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuochaoHN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值