• Java对象、类与内部类、匿名类


    原文:https://www.runoob.com/java/java-object-classes.html

    Java作为一种面向对象语言。支持以下基本概念:

    • 多态
    • 继承
    • 封装
    • 抽象
    • 对象
    • 实例
    • 方法
    • 重载

    本节我们重点研究对象和类的概念。

    • 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
    • :类是一个模板,它描述一类对象的行为和状态。

    下图中汽车类(class),而具体的每辆车为该汽车类的对象(object),对象包含了汽车的颜色、品牌、名称等。

    一、Java中的对象

    现在让我们深入了解什么是对象。看看周围真实的世界,会发现身边有很多对象,车,狗,人等等。所有这些对象都有自己的状态和行为。

    拿一条狗来举例,它的状态有:名字、品种、颜色,行为有:叫、摇尾巴和跑。

    对比现实对象和软件对象,它们之间十分相似。

    软件对象也有状态和行为。软件对象的状态就是属性,行为通过方法体现。

    在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。

    二、Java 中的类

    1、类的定义和介绍

    类可以看成是创建 Java 对象的模板。

    通过上图创建一个简单的类来理解下 Java 中类的定义:

    public class Dog {
        String breed;
        int size;
        String colour;
        int age;
     
        void eat() {
        }
     
        void run() {
        }
     
        void sleep(){
        }
     
        void name(){
        }
    }

    一个类可以包含以下类型变量:

    • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
    • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
    • 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。

    一个类可以拥有多个方法,在上面的例子中:eat()、run()、sleep() 和 name() 都是 Dog 类的方法。

    变量类型:

    1.局部变量:在方法、构造方法、语句块中定义的变量。其声明和初始化在方法中实现,在方法结束后自动销毁

    public class  ClassName{
        public void printNumber(){
            int a;
        }
        // 其他代码
    }

    2.成员变量:定义在类中,方法体之外。变量在创建对象时实例化。成员变量可被类中的方法、构造方法以及特定类的语句块访问。

    public class  ClassName{
        int a;
        public void printNumber(){
            // 其他代码
        }
    }

    3.类变量:定义在类中,方法体之外,但必须要有 static 来声明变量类型。静态成员属于整个类,可通过对象名或类名来调用。

    public class  ClassName{
        static int a;
        public void printNumber(){
            // 其他代码
        }
    }

    2、成员变量和类变量的区别

    由static修饰的变量称为静态变量,其实质上就是一个全局变量。如果某个内容是被所有对象所共享,那么该内容就应该用静态修饰;没有被静态修饰的内容,其实是属于对象的特殊描述。

    不同的对象的实例变量将被分配不同的内存空间, 如果类中的成员变量有类变量,那么所有对象的这个类变量都分配给相同的一处内存,改变其中一个对象的这个类变量会影响其他对象的这个类变量,也就是说对象共享类变量。

    成员变量和类变量的区别:

    1、两个变量的生命周期不同

          成员变量随着对象的创建而存在,随着对象的回收而释放。

          静态变量随着类的加载而存在,随着类的消失而消失。

    2、调用方式不同

          成员变量只能被对象调用。

          静态变量可以被对象调用,还可以被类名调用。

    3、别名不同

          成员变量也称为实例变量。

          静态变量也称为类变量。

    4、数据存储位置不同

          成员变量存储在堆内存的对象中,所以也叫对象的特有数据。

          静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

    static 关键字,是一个修饰符,用于修饰成员(成员变量和成员函数)。

    特点:

    1、想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。

    2、被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态方式。

    3、静态随着类的加载而加载。而且优先于对象存在。

    弊端:

    1、有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。

    2、静态方法只能访问静态成员,不可以访问非静态成员。

          因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。

    3、静态方法中不能使用this,super关键字。

          因为this代表对象,而静态在时,有可能没有对象,所以this无法使用。

    什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰呢?

    成员分两种:

    1、成员变量。(数据共享时静态化)

    该成员变量的数据是否是所有对象都一样:

    如果是,那么该变量需要被静态修饰,因为是共享的数据。 

    如果不是,那么就说这是对象的特有数据,要存储到对象中。 

    2、成员函数。(方法中没有调用特有数据时就定义成静态)

    如果判断成员函数是否需要被静态修饰呢?

    只要参考,该函数内是否访问了对象中的特有数据:

    如果有访问特有数据,那方法不能被静态修饰。

    如果没有访问过特有数据,那么这个方法需要被静态修饰。

    成员变量和静态变量的区别:

    1、成员变量所属于对象。所以也称为实例变量。静态变量所属于类。所以也称为类变量。

    2、成员变量存在于堆内存中。静态变量存在于方法区中。

    3、成员变量随着对象创建而存在。随着对象被回收而消失。静态变量随着类的加载而存在。随着类的消失而消失。

    4、成员变量只能被对象所调用 。静态变量可以被对象调用,也可以被类名调用。所以,成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。

    3、成员变量和局部变量的区别

    1.声明位置不同

    成员变量也就是属性,在类中声明的。

    局部变量,在方法中声明或代码块中声明。

    2.初始值不同

    成员变量如果没有赋值则是有默认值的,数据类型不同则默认值不同。

    局部变量是没有默认值,也就是说必须先声明,再赋值,最后才使用。

    3.在一个类中,局部变量可以与成员变量同名,但是局部变量优先,如果非要访问成员变量的属性,则必须使用 this.color

    this 代表当前这个对象,也就是当前谁调用这个方法则这个对象就是谁。

    三、构造方法

    每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。

    在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法

    如果有多个构造方法的时候,会根据实例化对象的入参去调用对应的构造方法。

    类的构造方法

    • 构造方法的名字和类名相同,并且没有返回值。
    • 构造方法主要用于为类的对象定义初始化状态。
    • 我们不能直接调用构造方法,必须通过new关键字来自动调用,从而创建类的实例。
    • Java的类都要求有构造方法,如果没有定义构造方法,Java编译器会为我们提供一个缺省的构造方法,也就是不带参数的构造方法。

    new关键字的作用

    1. 为对象分配内存空间。
    2. 引起对象构造方法的调用。
    3. 为对象返回一个引用。

    使用java类实例化一个对象的时候,如果在类中不显式的声明其构造函数,则会使用一个默认的构造函数来初始化对象。

    实例:

    //一个没有显式声明构造函数的类
    Public class People{
        int age = 23;
        Public void getAge(){
            System.out.print("the age is "+age);
        }
    }
    
    //用这个类来实例化一个对象
    People xiaoMing = new People(); // People() 是People类的默认构造函数,它什么也不干
    xiaoMing.getAge();//打印年龄

    也可以在声明类的时候显式的声明一个构造函数:

    //一个带显式构造函数的类
    Public class People{
        int age = 23;
        Public void getAge(){
            System.out.print("the age is "+ age);
        }
        // 显式声明一个带参数的构造函数,用于初始化年龄
        Public People(int a){
            this.age = a; 
        }
    }
    
    //用这个类来实例化一个对象
    People xiaoMing = new People(20); // 使用带参数的构造函数来实例化对象
    xiaoMing.getAge(); // 打印出来的年龄变为20

    一个类可以有多个构造方法:

    public class Test {
        public Test() {
            System.out.println("这个构造方法没有入参");
        }
    
        public Test(int num) {
            System.out.println("这个构造方法有一个整型参数num: " + num);
        }
    
        public Test(String name) {
            System.out.println("这个构造方法有一个字符串参数name: " + name);
        }
    
        public static void main(String[] args) {
            Test obj1 = new Test();  // 调用第1个构造方法
            Test obj2 = new Test(1);  // 调用第2个构造方法
            Test obj3 = new Test("小明");  // 调用第3个构造方法
        }
    }

    四、创建对象

    对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:

    • 声明:声明一个对象,包括对象名称和对象类型。
    • 实例化:使用关键字 new 来创建一个对象。
    • 初始化:使用 new 创建对象时,会调用构造方法初始化对象。

    下面是一个创建对象的例子:

    public class Puppy{
       public Puppy(String name){
          //这个构造器仅有一个参数:name
          System.out.println("小狗的名字是 : " + name ); 
       }
       public static void main(String[] args){
          // 下面的语句将创建一个Puppy对象
          Puppy myPuppy = new Puppy("tommy");
       }
    }

    编译并运行上面的程序,会打印出下面的结果:

    小狗的名字是 : tommy

    五、访问实例变量和方法

    通过已创建的对象来访问成员变量和成员方法,如下所示:

    /* 实例化对象 */
    Object referenceVariable = new Constructor();
    /* 访问类中的变量 */
    referenceVariable.variableName;
    /* 访问类中的方法 */
    referenceVariable.methodName();

    下面的例子展示如何访问实例变量和调用成员方法:

    public class Puppy {
        int puppyAge;
    
        public Puppy(String name) {
            // 这个构造器仅有一个参数:name
            System.out.println("小狗的名字是 : " + name);
        }
    
        public void setAge(int age) {
            puppyAge = age;
        }
    
        public int getAge() {
            System.out.println("小狗的年龄为 : " + puppyAge);
            return puppyAge;
        }
    
        public static void main(String[] args) {
            /* 创建对象 */
            Puppy myPuppy = new Puppy("tommy");
            /* 通过方法来设定age */
            myPuppy.setAge(2);
            /* 调用另一个方法获取age */
            myPuppy.getAge();
            /*你也可以像下面这样访问成员变量 */
            System.out.println("变量值 : " + myPuppy.puppyAge);
        }
    }

    编译并运行上面的程序,产生如下结果:

    小狗的名字是 : tommy
    小狗的年龄为 : 2
    变量值 : 2

    六、内部类

    https://www.runoob.com/java/java-inner-class.html

    内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类。

    如同一个人是由大脑、肢体、器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行为(血液、跳动)。

    显然,此处不能单方面用属性或者方法表示一个心脏,而需要一个类。

    而心脏又在人体当中,正如同是内部类在外部内当中。

    Java 一个类中可以嵌套另外一个类,语法格式如下:

    class OuterClass {   // 外部类
        // ...
        class NestedClass { // 嵌套类,或称为内部类
            // ...
        }
    }

    要访问内部类,可以通过创建外部类的对象,然后创建内部类的对象来实现。

    嵌套类有两种类型:

    • 非静态内部类
    • 静态内部类

    1、非静态内部类

    非静态内部类是一个类中嵌套着另外一个类。 它有访问外部类成员的权限, 通常被称为内部类。

    由于内部类嵌套在外部类中,因此必须首先实例化外部类,然后创建内部类的对象来实现。

    class OuterClass {
        int x = 10;
    
        class InnerClass {
            int y = 5;
    
            public InnerClass() {
                // 内部类访问外部类的成员变量:外部类.this.成员变量
                System.out.println(OuterClass.this.x);
            }
        }
    }
    
    public class MyMainClass {
        public static void main(String[] args) {
            OuterClass myOuter = new OuterClass();
            OuterClass.InnerClass myInner = myOuter.new InnerClass();
            System.out.println(myInner.y + myOuter.x);
        }
    }

    以上实例执行输出结果为:

    10
    15

    2、私有的内部类

    内部类可以使用 private 或 protected 来修饰,如果你不希望内部类被外部类访问可以使用 private 修饰符:

    class Out {
        private int age = 12;
    
        private class In {
            public void print() {
                System.out.println(age);
            }
        }
    
        public void outPrint() {
            new In().print();
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            /* 此方法无效
             * Out.In in = new Out().new In();
             * in.print();
             */
            Out out = new Out();
            out.outPrint();
        }
    }

    运行结果:12

    如果一个内部类只希望被外部类中的方法操作,那么可以使用 private 声明内部类。

    上面的代码中,我们必须在 Out 类里面生成 In 类的对象进行操作,而无法再使用 Out.In in = new Out().new In() 生成内部类的对象。

    也就是说,此时的内部类只有外部类可控制。

    如同是,我的心脏只能由我的身体控制,其他人无法直接访问它。

    3、方法内部类

    class Out {
        private int age = 12;
    
        public void Print(final int x) {
            class In {
                public void inPrint() {
                    System.out.println(x);
                    System.out.println(age);
                }
            }
            new In().inPrint();
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            Out out = new Out();
            out.Print(3);
        }
    }

    运行结果:

    3
    12

    在上面的代码中,我们将内部类移到了外部类的方法中,然后在外部类的方法中再生成一个内部类对象去调用内部类方法。

    如果此时我们需要往外部类的方法中传入参数,那么外部类的方法形参必须使用 final 定义。

    至于 final 在这里并没有特殊含义,只是一种表示形式而已。

    4、静态内部类

    静态内部类注意点:

    • 静态内部类中可以有非静态的方法。
    • 当内部类中有静态方法或者静态成员变量时,一定是静态内部类。

    静态内部类可以使用 static 关键字定义,静态内部类我们不需要创建外部类来访问,可以直接访问它:

    class OuterClass {
        int x = 10;
        private static int age = 12;
    
        static class InnerClass {
            int y = 5;
    
            public InnerClass() {
                // 静态内部类访无法问外部类的成员变量,因此注释这行(java: 无法从静态上下文中引用非静态 变量 this)
                // System.out.println(OuterClass.this.x);
    
                // 但是可以访问外部类的静态成员变量
                System.out.println(age);
            }
    
            public void getY() {
                // 即使是静态内部类的非静态方法也是无法访问外部类的成员变量
                // System.out.println(OuterClass.this.x);
                System.out.println(y);
            }
        }
    }
    
    public class MyMainClass {
        public static void main(String[] args) {
            OuterClass.InnerClass myInner = new OuterClass.InnerClass();
            myInner.getY();
        }
    }

    以上实例执行输出结果为:

    12
    5

    注意:

    可以看到,如果用 static 将内部类静态化,那么内部类就只能访问外部类的静态成员变量,具有局限性。

    其次,因为内部类被静态化,因此 OuterClass.InnerClass 可以当做一个整体看,可以直接 new 出内部类的对象(通过类名访问 static,生不生成外部类对象都没关系)

    5、内部类和外部类之间的相互调用

    原文:https://www.cnblogs.com/jpfss/p/10993126.html

    内部类的一般格式

    public class Outer {
        class Inner{
    
        }
    }

    调用方式:

    1.外部类访问内部类
    内部类被static修饰:可以直接new
        Inner in = new Inner();

    内部类没有被static修饰:先new外部类的实例,再new内部类实例
        Inner in = new Outer().new Inner();

    2.内部类访问外部类
    变量或者函数名不同的情况下
        直接使用:外部类变量或者函数

    变量或者函数名相同的情况下
        外部类.this.变量或者函数

    也就是说:

    内部类在没有同名成员变量和局部变量的情况下,内部类会直接访问外部类的成员变量,而无需指定Out.this.属性名。

    否则,内部类中的局部变量会覆盖外部类的成员变量

    访问内部类本身的成员变量可用 this.属性名访问外部类的成员变量需要使用 Out.this.属性名。

    内部类访问外部类:内部类可以直接访问外部类的成员包括私有成员,因为外部类持有内部类的引用

    public class Outer {
        int x = 9;
    
        private class Inner {
            int x = 8;
    
            /*
             * 内部类访问外部类的成员变量和函数
             */
            private void test() {
                int x = 7;
                System.out.println("inner class method x: " + x);  // 内部类函数局部变量
                System.out.println("inner class x: " + this.x);  // 内部类成员变量
                System.out.println("outer class x: " + Outer.this.x);  // 外部类成员变量
                testing();  // 访问内部类的函数
                Outer.this.testing();  // 如果外部类函数名跟内部类函数同名:外部类.this.函数()
                testingOut();  // 如果外部类函数名跟内部类函数不是同名可以直接使用:函数()
            }
    
            private void testing() {
                System.out.println("test inner");
            }
        }
    
        private void testing() {
            System.out.println("test outer");
        }
    
        private void testingOut() {
            System.out.println("testingOut");
        }
    
        public static void main(String[] args) {
            Inner inner = new Outer().new Inner();
            inner.test();
        }
    }

    结果:

    inner class method x: 7
    inner class x: 8
    outer class x: 9
    test inner
    test outer
    testingOut

    注意:内部类可以调用外部类private方法是因为实际他们都是在同一个类Outer中,因此可以调用

    外部类访问内部类:必须建立内部类的对象

    public class Outer {
        int x = 9;
    
        private class Inner {
            int x = 8;
    
            /*
             * 内部类访问外部类的成员变量
             */
            private void test() {
                int x = 7;
                System.out.println("inner class method x: " + x);  // 内部类函数局部变量
                System.out.println("inner class x: " + this.x);  // 内部类成员变量
                System.out.println("outer class x: " + Outer.this.x);  // 外部类成员变量
            }
        }
    
        private void testingOut() {
            System.out.println("外部类方法调用内部类方法");
            Inner inner = new Inner();
            inner.test();
        }
    
        public static void main(String[] args) {
            Outer outer = new Outer();
            outer.testingOut();
        }
    }

    结果:

    外部类方法调用内部类方法
    inner class method x: 7
    inner class x: 8
    outer class x: 9

    七、匿名类

    https://www.runoob.com/java/java-anonymous-class.html

    Java 中可以实现一个类中包含另外一个类,且不需要提供任何的类名直接实例化。

    主要是用于在我们需要的时候创建一个对象来执行特定的任务,可以使代码更加简洁。

    匿名类是不能有名字的类,它们不能被引用,只能在创建时用 new 语句来声明它们。

    匿名类语法格式:

    class outerClass {
    
        // 定义一个匿名类
        object1 = new Type(parameterList) {
             // 匿名类代码
        };
    }

    以上的代码创建了一个匿名类对象 object1,匿名类是表达式形式定义的,所以末尾以分号 ; 来结束。

    匿名类通常继承一个父类或实现一个接口。

    1、匿名类继承一个父类

    以下实例中,创建了 Polygon 类,该类有一个方法 display(),AnonymousDemo 类继承了 Polygon 类并重写了 Polygon 类的 display() 方法:

    class Polygon {
        public void display() {
            System.out.println("在 Polygon 类内部");
        }
    
        public void balala() {
            System.out.println("在 Polygon 类内部 balala");
        }
    }
    
    class AnonymousDemo {
        public void createClass() {
            // 创建的匿名类继承了 Polygon 类
            Polygon p1 = new Polygon() {
                public void display() {
                    System.out.println("在匿名类内部。");
                }
            };
            p1.display();  // 调用的是重写后的方法
            p1.balala();  // 调用父类的方法
        }
    }
    
    class Main {
        public static void main(String[] args) {
            AnonymousDemo an = new AnonymousDemo();
            an.createClass();
        }
    }

    执行以上代码,匿名类的对象 p1 会被创建,该对象会调用匿名类的 display() 方法,输出结果为:

    在匿名类内部。
    在 Polygon 类内部 balala

    2、匿名类实现一个接口

    以下实例创建的匿名类实现了 Polygon 接口:

    interface Polygon {
        public void display();
    }
    
    class AnonymousDemo {
        public void createInterface() {
            // 匿名类实现一个接口
            Polygon p1 = new Polygon() {
                public void display() {
                    System.out.println("在匿名类内部。");
                }
            };
            p1.display();
        }
    }
    
    class Main {
        public static void main(String[] args) {
            AnonymousDemo an = new AnonymousDemo();
            an.createInterface();
        }
    }

    输出结果为:

    在匿名类内部。
  • 相关阅读:
    使用sql语句查询表结构
    plsql出现录相机后卡屏解决方法
    oracle的“ORA-01480:STR绑定值的结尾Null字符缺失”错误
    oracle创建表空间并对用户赋权
    Scrapy安装错误(error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools)
    震惊你不知道的python
    django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'
    python3 ImportError: No module named 'ConfigParser'
    python import报错
    No migrations to apply(django不能创建数据库中的表的问题)
  • 原文地址:https://www.cnblogs.com/Zzbj/p/16636792.html
Copyright © 2020-2023  润新知