Java官方笔记4类和对象

news2024/11/17 19:42:59

创建类

定义类Bicycle:

public class Bicycle {

    // the Bicycle class has
    // three fields
    public int cadence;
    public int gear;
    public int speed;

    // the Bicycle class has
    // one constructor
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }

    // the Bicycle class has
    // four methods
    public void setCadence(int newValue) {
        cadence = newValue;
    }

    public void setGear(int newValue) {
        gear = newValue;
    }

    public void applyBrake(int decrement) {
        speed -= decrement;
    }

    public void speedUp(int increment) {
        speed += increment;
    }
}

创建子类MountainBike继承类Bicycle:

public class MountainBike extends Bicycle {

    // the MountainBike subclass has
    // one field
    public int seatHeight;

    // the MountainBike subclass has
    // one constructor
    public MountainBike(int startHeight, int startCadence,
                        int startSpeed, int startGear) {
        super(startCadence, startSpeed, startGear);
        seatHeight = startHeight;
    }   

    // the MountainBike subclass has
    // one method
    public void setHeight(int newValue) {
        seatHeight = newValue;
    }   
}

可以看出定义类的语法如下:

class MyClass {
    // field, constructor, and 
    // method declarations
}

复杂点的:

class MyClass extends MySuperClass implements YourInterface {
    // field, constructor, and
    // method declarations
}

定义了类MyClass继承类MySuperClass,并实现接口YourInterface。类只能有一个父类,但是能实现多个接口。

定义方法

方法定义示例:

public double calculateAnswer(double wingSpan, int numberOfEngines,
                              double length, double grossTons) {
    //do the calculation here
}

方法签名,方法名+参数类型,比如上面的方法签名是:

calculateAnswer(double, int, double, double)

1个类中可以有多个同名的,但是不同参数的方法,也就是方法重载:

public class DataArtist {
    ...
    public void draw(String s) {
        ...
    }
    public void draw(int i) {
        ...
    }
    public void draw(double f) {
        ...
    }
    public void draw(int i, double f) {
        ...
    }
}

但是方法重载应谨慎使用,它会降低代码可读性。

类构造器

类有个默认的无参数的构造器,也可以自定义:

public Bicycle(int startCadence, int startSpeed, int startGear) {
    gear = startGear;
    cadence = startCadence;
    speed = startSpeed;
}

构造器跟类同名,没有return。类可以有多个不同参数列表的构造器。

调用

参数定义的叫做Parameters ,实际传入的叫做Arguments

基本数据类型

public double computePayment(
                  double loanAmt,
                  double rate,
                  double futureValue,
                  int numPeriods) {
    double interest = rate / 100.0;
    double partial1 = Math.pow((1 + interest), 
                    - numPeriods);
    double denominator = (1 - partial1) / interest;
    double answer = (-loanAmt / denominator)
                    - ((futureValue * partial1) / denominator);
    return answer;
}

类对象

public Polygon polygonFrom(Point[] corners) {
    // method body goes here
}

可变参数

public Polygon polygonFrom(Point... corners) {
    int numberOfSides = corners.length;
    double squareOfSide1, lengthOfSide1;
    squareOfSide1 = (corners[1].x - corners[0].x)
                     * (corners[1].x - corners[0].x) 
                     + (corners[1].y - corners[0].y)
                     * (corners[1].y - corners[0].y);
    lengthOfSide1 = Math.sqrt(squareOfSide1);

    // more method body code follows that creates and returns a 
    // polygon connecting the Points
}

使用...来表示可变参数。

方法中的基本数据类型,return后消失:

public class PassPrimitiveByValue {

    public static void main(String[] args) {

        int x = 3;

        // invoke passMethod() with 
        // x as argument
        passMethod(x);

        // print x to see if its 
        // value has changed
        System.out.println("After invoking passMethod, x = " + x);

    }

    // change parameter in passMethod()
    public static void passMethod(int p) {
        p = 10;
    }
}

方法中的引用类型,return后还有作用到原来的对象:

public class RefType {
    public void moveCircle(Circle circle, int deltaX, int deltaY) {
        // code to move origin of circle to x+deltaX, y+deltaY
        circle.setX(circle.getX() + deltaX);
        circle.setY(circle.getY() + deltaY);

        // code to assign a new reference to circle
        circle = new Circle(0, 0);
    }

    public static void main(String[] args) {
        Circle circle = new Circle(1, 1);
        RefType refType = new RefType();
        refType.moveCircle(circle, 2, 2);
        System.out.println(circle.getX());
    }
}

运行结果为3。moveCircle里面的circle,set方法调用会影响到引用的对象。虽然最后new了一个新对象,但是赋值给的是方法内部的这个circle,return后消失,外面的circle不受影响。可以这么理解,外面和里面的两个circle,引用的都是同一个对象。

对象

创建对象:

Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);

变量声明:

type name;

如果是基本数据类型,则会先分配内存空间。如果是类引用,则不会,在new的时候才会分配内存空间。

字段:

objectReference.fieldName

方法:

objectReference.methodName(argumentList);

请记住,一个对象能有多个引用。

类的高级用法

方法退出有3种情况:

  1. 代码执行完

  2. throw异常

  3. return

返回类型如果是类,那么可以return子类。返回类型如果是接口,那么可以return接口实现类。

this关键字表示当前类,或用来调用其他构造方法:

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(0, 0, 1, 1);
    }
    public Rectangle(int width, int height) {
        this(0, 0, width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    ...
}

调用其他构造方法必须放在第一行。

范围控制

top级别:public、package-private

member级别:public、private、protected、package-private

其中注意protected,等于package-private + 其他包中的子类(继承了当前类,但是在其他包里面)

怎么理解?在自己的地盘(package)随便玩,但是到了其他地盘,必须有父类保护(protected)

第3列的Subclass指的是其他包的子类。

访问控制有2个用途:

  1. 在用别人的类时,看哪些可以使用

  2. 定义自己的类时,决定哪些允许别人用

static关键字,创建类字段:

public class Bicycle {

    private int cadence;
    private int gear;
    private int speed;
    private int id;
    private static int numberOfBicycles = 0;

    public Bicycle(int startCadence, int startSpeed, int startGear){
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;

        // increment number of Bicycles
        // and assign ID number
        id = ++numberOfBicycles;
    }

    // new method to return the ID instance variable
    public int getID() {
        return id;
    }
        ...
}

可以直接用类名访问:

Bicycle.numberOfBicycles

static关键字

创建类方法:

public static int getNumberOfBicycles() {
    return numberOfBicycles;
}

创建常量:

static final double PI = 3.141592653589793;

注意,基本数据类型或string的常量,会在编译的时候直接替换。如果依赖外部包的常量值变化了,比如PI变成了3.9,那么当前代码需要重新编译。

关于static,有一个很重要的点是:static只能访问static,也就是class级别只能访问class级别,如果想访问member级别,必须实例化对象后通过引用来访问。

static块

对于字段初始化来说,如果想写多行代码来初始化(比如写个for循环来填充复杂数组),instance级别可以在构造函数来做,而对于class级别呢?就可以使用static块:

public class MyClass {
    public static int x;
    public static int y;

    static {
        x = 10;
        y = 20;
        System.out.println("静态块执行");
    }

    public static void main(String[] args) {
        System.out.println("x=" + x);
        System.out.println("y=" + y);
    }
}

static块是用来给class级别字段做值初始化的,它们会按照在类中出现的顺序依次执行,并且它们在构造函数之前执行。

也可以定义static方法后赋值:

class Whatever {
    public static varType myVar = initializeClassVariable();

    private static varType initializeClassVariable() {

        // initialization code goes here
    }
}

member级别字段初始化块,也就是不带static的:

{
    // whatever code is needed for initialization goes here
}

会在每个constructor中执行。也可以使用final方法:

class Whatever {
    private varType myVar = initializeInstanceVariable();

    protected final varType initializeInstanceVariable() {

        // initialization code goes here
    }
}

为什么这里必须要用final?因为在实例初始化期间调用非final方法会报错,这是为了提高代码健壮性、可读性和可维护性,初始化本来就是一个确定的事情,那么就用final限定清楚。

嵌套类

class OuterClass {
    ...
    class InnerClass {
        ...
    }
    static class StaticNestedClass {
        ...
    }
}

InnerClass能访问OutClass所有成员(可以理解为跟method类似),StaticNestedClass则不能。

什么情况需要用嵌套类?

  • 这个类只会被另外1个类使用,那么可以定义为嵌套类(helper classes),优化包结构

  • 封装,嵌套类可以访问内部private成员

  • 可读性,小的嵌套类,方便阅读

必须先实例化OuterClass再实例化InnerClass:

OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

而static嵌套类跟普通类一样:

StaticNestedClass staticNestedObject = new StaticNestedClass();

注意,static嵌套类,跟其他顶层类是一样的,意味着它不能直接访问所在类的字段,而必须通过实例化对象引用才能访问。(也许是为了方便在一个文件里面写多个类,才设计了static嵌套类)

以下是示例:

OuterClass.java

public class OuterClass {

    String outerField = "Outer field";
    static String staticOuterField = "Static outer field";

    class InnerClass {
        void accessMembers() {
            System.out.println(outerField);
            System.out.println(staticOuterField);
        }
    }

    static class StaticNestedClass {
        void accessMembers(OuterClass outer) {
            // Compiler error: Cannot make a static reference to the non-static
            //     field outerField
            // System.out.println(outerField);
            System.out.println(outer.outerField);
            System.out.println(staticOuterField);
        }
    }

    public static void main(String[] args) {
        System.out.println("Inner class:");
        System.out.println("------------");
        OuterClass outerObject = new OuterClass();
        OuterClass.InnerClass innerObject = outerObject.new InnerClass();
        innerObject.accessMembers();

        System.out.println("\nStatic nested class:");
        System.out.println("--------------------");
        StaticNestedClass staticNestedObject = new StaticNestedClass();
        staticNestedObject.accessMembers(outerObject);

        System.out.println("\nTop-level class:");
        System.out.println("--------------------");
        TopLevelClass topLevelObject = new TopLevelClass();
        topLevelObject.accessMembers(outerObject);
    }
}

TopLevelClass.java

public class TopLevelClass {

    void accessMembers(OuterClass outer) {
        // Compiler error: Cannot make a static reference to the non-static
        //     field OuterClass.outerField
        // System.out.println(OuterClass.outerField);
        System.out.println(outer.outerField);
        System.out.println(OuterClass.staticOuterField);
    }
}

一个变量引用的例子,这个例子展示了不同级别的同名变量,是如何取值的:

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}
x = 23
this.x = 1
ShadowTest.this.x = 0  // 注意这种在嵌套类取OuterClass同名字段的方式

Local Class,定义在method里面的嵌套类:

public class LocalClassExample {

    static String regularExpression = "[^0-9]";

    public static void validatePhoneNumber(
        String phoneNumber1, String phoneNumber2) {

        final int numberLength = 10;

        // Valid in JDK 8 and later:

        // int numberLength = 10;

        class PhoneNumber {

            String formattedPhoneNumber = null;

            PhoneNumber(String phoneNumber){
                // numberLength = 7;
                String currentNumber = phoneNumber.replaceAll(
                  regularExpression, "");
                if (currentNumber.length() == numberLength)
                    formattedPhoneNumber = currentNumber;
                else
                    formattedPhoneNumber = null;
            }

            public String getNumber() {
                return formattedPhoneNumber;
            }

            // Valid in JDK 8 and later:

//            public void printOriginalNumbers() {
//                System.out.println("Original numbers are " + phoneNumber1 +
//                    " and " + phoneNumber2);
//            }
        }

        PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);
        PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);

        // Valid in JDK 8 and later:

//        myNumber1.printOriginalNumbers();

        if (myNumber1.getNumber() == null)
            System.out.println("First number is invalid");
        else
            System.out.println("First number is " + myNumber1.getNumber());
        if (myNumber2.getNumber() == null)
            System.out.println("Second number is invalid");
        else
            System.out.println("Second number is " + myNumber2.getNumber());

    }

    public static void main(String... args) {
        validatePhoneNumber("123-456-7890", "456-7890");
    }
}

Local Class只能访问方法里面的final变量,或者“看似final”的变量(值不会发生变化)。否则会报错:local variables referenced from an inner class must be final or effectively final。但是能直接方法参数列表的parameters。

Anonymous Class,定义在method里面的没有名字的嵌套类:

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        HelloWorld frenchGreeting = new HelloWorld() {  // 匿名类
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        HelloWorld spanishGreeting = new HelloWorld() {  // 匿名类
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }
}

它的语法跟constructor类似,new后面跟上implements接口或extends类的名字,但它是一个表达式,所以最后要加上分号。

请记住,Local Class和Anonymous Class,都是应以在method里面的。

参考资料:

Classes and Objects https://dev.java/learn/classes-objects/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/604685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

李沐动手学习深度学习 2023年Win10 下安装 CUDA 和 Pytorch 跑深度学习(最新)

目录 一、安装Anaconda 1.下载Anaconda 测试是否安装成功 二、安装pytorch 验证pytorch是否安装成功 4.测试 3.配置pycharm 一、安装Anaconda 1.下载Anaconda 可以在官网下载,但是速度较慢,这里我选择了清华镜像源的下载 https://mirrors.tuna.t…

Gradio的web界面演示与交互机器学习模型,Blocks的事件侦听《7》

在第一篇文章我们就熟悉了Blocks的用法,使用Blocks比Interface更加灵活,这节重点关注Blocks里面的相关操作。 1、Blocks标准例子 import gradio as grdef greet(name):return "你好 " name "!"with gr.Blocks() as demo:name g…

简单的汉诺塔,神奇的预言,竟然需要5849亿年???(52)

小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 和猫妹学Python,一起趣味学编程。 今日主题 汉诺塔 古印度大梵天传说 Python玩转汉诺塔 递归 汉诺塔 汉诺塔(Hanoi)是一个著名的益智游戏,也称…

规则引擎架构-基于aviator

目录 aviator使用场景ASM 字节码操控框架aviator 表达式例子debug表达式类生成过程b-ca生成的class文件 aviator使用场景 github地址:aviator 使用场景: 规则判断及规则引擎公式计算动态脚本控制集合数据 ELT 等 …… ASM 字节码操控框架 asm实现&a…

【Dubbo】Dubbo架构的演进过程分析

📫作者简介:小明java问道之路,2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于…

Go并发编程 Goroutine、Channel、Select、Mutex锁、sync、Atomic等

本文所有实例代码运行go版本:go version go1.18.10 windows/amd64 1 并发编程介绍 1.1 串行、并发、并行 串行:所有任务一件一件做,按照事先的顺序依次执行,没有被执行到的任务只能等待。最终执行完的时间等于各个子任务之和。…

效率神器!神级ChatGPT浏览器插件分享

大家好,我是卷了又没卷,薛定谔的卷的AI算法工程师「陈城南」~ 担任某大厂的算法工程师,带来最新的前沿AI知识和工具,欢迎大家交流~,后续我还会分享更多 AI 有趣工具和实用玩法,包括AI相关技术、ChatGPT、AI…

初识SpringBoot -- SpringBoot入门保姆级教程(一)

文章目录 前言一、初识SpringBoot1.SpringBoot简介2.用编译器IDEA创建SpringBoot项目3.在官网创建SpringBoot项目4.SpringBoot项目快速启动(前后端分离基本能力)5.了解SpringBoot起步依赖和启动类 总结 前言 为了巩固所学的知识,作者尝试着开…

RocketMQ消息消费

RocketMQ消息消费示例代码: public static void main(String[] args) throws InterruptedException, MQClientException {DefaultMQPushConsumer consumer new DefaultMQPushConsumer("please_rename_unique_group_name_4");consumer.setNamesrvAddr(&qu…

C++ 学习 ::【基础篇:15】:C++ 类的基本成员函数:析构顺序问题(全局/静态/局部量) 及 类类型(自定义类型)与析构函数

本系列 C 相关文章 仅为笔者学习笔记记录,用自己的理解记录学习!C 学习系列将分为三个阶段:基础篇、STL 篇、高阶数据结构与算法篇,相关重点内容如下: 基础篇:类与对象(涉及C的三大特性等&#…

Nginx配置块location及rewrite详解(遗憾)

文章目录 一、location配置块详解1.location 大致分为三类2.location 常用的匹配规则3.location 匹配的优先级4.location 匹配流程5.location 的实际使用(1)直接匹配网站根目录首页(2)处理静态文件请求(3)通…

函数式接口相关知识点

这里写目录标题 函数式接口简介以及注意点函数式接口作为方法的参数函数式接口作为方法参数常用的函数式接口Supplier简介具体代码操作 Consumer简介具体代码演示演示1演示2 Predicate接口简介以及接口中的方法text和negate方法and和or方法Function方法简介具体操作1具体操作2 …

SQL语句之DDL语言

说明:DDL(Data Definition Language,数据定义语言),用来定义数据库对象(数据库、表),包括了数据库和表的创建、查询、使用和删除操作。 一、数据库操作 新安装的数据库,默认有以下四个数据库&…

计算机网络-数据链路层

概念 结点:主机、路由器 链路:结点间物理通道 数据链路:结点间逻辑通道,控制数据传输协议的硬件和软件加到链路上构成数据链路 帧:链路层的协议数据单元,封装网络层数据报 数据链路层负责通过一条链路从一…

银行转账问题(死锁)

本文主要讲述死锁的一个经典案例—银行转账问题,并对该问题进行定位、修复。 1. 问题说明 当账户A对账户B进行转账时, 首先需要获取到两把锁:账户A和账户B的锁。获取两把锁成功,且余额大于0,则扣除转出人的余额&…

我记不住的那些C语言的struct知识

背景: 最近在重学C语言,目的是为了能看懂操作系统的底层代码,也为后续使用C语言开发一个类似redis数据库的中间件做准备,于是又重新踏上了学习C语言的道路,早在上学期间就学习过C语言,但是很久都不用了&…

ssm学习-spring01

Spring_day01 今日目标 掌握Spring相关概念完成IOC/DI的入门案例编写掌握IOC的相关配置与使用掌握DI的相关配置与使用1,课程介绍 对于一门新技术,我们需要从为什么要学、学什么以及怎么学这三个方向入手来学习。那对于Spring来说: 1.1 为什么要学? 从使用和占有率看 Spri…

使用 ChatGPT API 构建系统(一):分类

今天我学习了DeepLearning.AI的 Building Systems with the ChatGPT API 的在线课程,我想和大家一起分享一下该门课程的一些主要内容。 下面是我们通过Openai API来访问ChatGPT模型的主要代码: import openai#您的openai的api key openai.api_key YOUR…

chatgpt赋能python:Python删除节点:从入门到实践

Python删除节点:从入门到实践 在任何编程语言中,删除节点都是一个极为常见的操作。在Python中,它同样非常重要,因为我们通常会使用Python处理各种数据结构,诸如树、链表等等。但是,删除节点并不总是一件容…

C++类和对象 -- 知识点补充

补充 const成员函数static成员友元内部类匿名对象拷贝对象时的一些编译器优化 const成员函数 将const修饰的成员函数称为const成员函数,const修饰类成员函数,实际是修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的成员进行修改。…