`
holdbelief
  • 浏览: 705971 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

第二课时:数组、面向对象(1)

阅读更多

一、数组

    1、数组也是一种类型

    2、数组的定义

    3、数组的初始化:静态初始化和动态初始化

      两种初始化的语法

      动态初始化时,系统分配的默认值:

        byte、short、int 和 long     —— 0

        float、double         —— 0.0

        char             —— '\u0000'

        boolean           —— false

        类、接口、数组                           —— null

    4、如何使用数组

    5、JDK1.5 提供的 foreach 循环

        for (type variableName : array | collection) {

            // ...

        }

        使用 foreach 时,不能对数组元素赋值。

    6、数组在内存中的存储方式

    7、操纵数组的工具类:

二、面向对象(1)

    1、类和对象

    面向对象的三大特征:封装、继承、多态。

    定义类的语法;类的访问修饰符:public、final

    类最常见的三个成员:构造器、属性、方法

    static修饰的类成员不能访问非static修饰的成员

    Java语言提供了一个功能:如果程序员没有为一个类编写构造器,则系统会为该类提供一个默认的构造器。一旦程序员为一个类提供了构造器,系统将不再为该类提供构造器。

    几个访问修饰符:public、private、protected、static、final、abstract 。这里重点讲一下 static 和 abstract 两个。

    static 修饰的成员表明它是属于这个类共有的,而不是属于这个类的单个实例,因此通常把 static 修饰的属性和方法也称为类属性、类方法(静态属性、静态方法)。不使用 static 修饰的普通方法、属性则属于该类的单个实例,而不是属于该类。因此通常把不使用 static 修饰的属性和方法也称为实例属性、实例方法(非静态属性、非静态方法)。      abstract 只声明不定义一个方法。

    构造器的语法和注意事项:1)修饰符可以是private、public、protected;2)名字必须与类名相同;3)不能有返回值;4)方法体内不能有 return

    构造器的重载,这里可以写多个重载示例让学生练习,体会重载构造器,使用各种不同的构造器实例化对象的好处和优越性,配合getter、setter方法。

    引用和对象在堆内存和栈内存中的存储方式。

    this 关键字是一个对象的默认引用。this 关键字总是指向调用该方法的对象。

    this 与 static 之间的矛盾。

    Java 是静态语言,它与动态语言,例如 JavaScript 的区别。 

    Java 方法的参数传递机制:只有一种——值传递。有关栈内存和堆内存。

    形参长度可变的方法:以下是参考文献

(本文转载自csdn)


到J2SE 1.4为止,一直无法在Java程序里定义实参个数可变的方法——因为Java要求实参(Arguments)和形参(Parameters)的数量和类型都必须逐一匹配,而形参的数目是在定义方法时就已经固定下来了。尽管可以通过重载机制,为同一个方法提供带有不同数量的形参的版本,但是这仍然不能达到让实参数量任意变化的目的。

然而,有些方法的语义要求它们必须能接受个数可变的实参——例如著名的main方法,就需要能接受所有的命令行参数为实参,而命令行参数的数目,事先根本无法确定下来。

 

对于这个问题,传统上一般是采用“利用一个数组来包裹要传递的实参”的做法来应付。

 

1. 用数组包裹实参

“用数组包裹实参”的做法可以分成三步:首先,为这个方法定义一个数组型的参数;然后在调用时,生成一个包含了所有要传递的实参的数组;最后,把这个数组作为一个实参传递过去。

这种做法可以有效的达到“让方法可以接受个数可变的参数”的目的,只是调用时的形式不够简单。

J2SE 1.5中提供了Varargs机制,允许直接定义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。

Varargs的含义

大体说来,“Varargs”是“variable number of arguments”的意思。有时候也被简单的称为“variable arguments”,不过因为这一种叫法没有说明是什么东西可变,所以意义稍微有点模糊。

 

2. 定义实参个数可变的方法

只要在一个形参的“类型”与“参数名”之间加上三个连续的“.”(即“...”,英文里的句中省略号),就可以让它和不确定个实参相匹配。而一个带有这样的形参的方法,就是一个实参个数可变的方法。

清单1:一个实参个数可变的方法

private static int sumUp(int... values) {
}

注意,只有最后一个形参才能被定义成“能和不确定个实参相匹配”的。因此,一个方法里只能有一个这样的形参。另外,如果这个方法还有其它的形参,要把它们放到前面的位置上。

编译器会在背地里把这最后一个形参转化为一个数组形参,并在编译出的class文件里作上一个记号,表明这是个实参个数可变的方法。

清单2:实参个数可变的方法的秘密形态

private static int sumUp(int[] values) {
}

由于存在着这样的转化,所以不能再为这个类定义一个和转化后的方法签名一致的方法。

清单3:会导致编译错误的组合

private static int sumUp(int... values) {
}
private static int sumUp(int[] values) {
}

3. 调用实参个数可变的方法

只要把要传递的实参逐一写到相应的位置上,就可以调用一个实参个数可变的方法。不需要其它的步骤。

清单4:可以传递若干个实参

sumUp(1, 3, 5, 7);

在背地里,编译器会把这种调用过程转化为用“数组包裹实参”的形式:

清单5:偷偷出现的数组创建

sumUp(new int[]{1, 2, 3, 4});

另外,这里说的“不确定个”也包括零个,所以这样的调用也是合乎情理的:

清单6:也可以传递零个实参

sumUp();

这种调用方法被编译器秘密转化之后的效果,则等同于这样:

清单7:零实参对应空数组

sumUp(new int[]{});

注意这时传递过去的是一个空数组,而不是null。这样就可以采取统一的形式来处理,而不必检测到底属于哪种情况。

4. 处理个数可变的实参

处理个数可变的实参的办法,和处理数组实参的办法基本相同。所有的实参,都被保存到一个和形参同名的数组里。根据实际的需要,把这个数组里的元素读出之后,要蒸要煮,就可以随意了。

 

清单8:处理收到的实参们

private static int sumUp(int... values) {
 int sum = 0;
 for (int i = 0; i < values.length; i++) {
  sum += values[i];
 }
 return sum;
}

 

5. 转发个数可变的实参

有时候,在接受了一组个数可变的实参之后,还要把它们传递给另一个实参个数可变的方法。因为编码时无法知道接受来的这一组实参的数目,所以“把它们逐一写到该出现的位置上去”的做法并不可行。不过,这并不意味着这是个不可完成的任务,因为还有另外一种办法,可以用来调用实参个数可变的方法。

在J2SE 1.5的编译器的眼中,实参个数可变的方法是最后带了一个数组形参的方法的特例。因此,事先把整组要传递的实参放到一个数组里,然后把这个数组作为最后一个实参,传递给一个实参个数可变的方法,不会造成任何错误。借助这一特性,就可以顺利的完成转发了。

清单9:转发收到的实参们

public class PrintfSample {
  public static void main(String[] args) {
    printOut("Pi:%f E:%f\n", Math.PI, Math.E);
  }
  private static void printOut(String format, Object... args) {
    System.out.printf(format, args);
 }
}

6. 是数组?不是数组?

尽管在背地里,编译器会把能匹配不确定个实参的形参,转化为数组形参;而且也可以用数组包了实参,再传递给实参个数可变的方法;但是,这并不表示“能匹配不确定个实参的形参”和“数组形参”完全没有差异。

一个明显的差异是,如果按照调用实参个数可变的方法的形式,来调用一个最后一个形参是数组形参的方法,只会导致一个“cannot be applied to”的编译错误。

清单10:一个“cannot be applied to”的编译错误

private static void testOverloading(int[] i) {
System.out.println("A");
}
public static void main(String[] args) {
testOverloading(1, 2, 3);//编译出错
}

由于这一原因,不能在调用只支持用数组包裹实参的方法的时候(例如在不是专门为J2SE 1.5设计第三方类库中遗留的那些),直接采用这种简明的调用方式。

如果不能修改原来的类,为要调用的方法增加参数个数可变的版本,而又想采用这种简明的调用方式,那么可以借助“引入外加函数(Introduce Foreign Method)”和“引入本地扩展(Intoduce Local Extension)”的重构手法来近似的达到目的。

 

7. 当个数可变的实参遇到泛型

J2SE 1.5中新增了“泛型”的机制,可以在一定条件下把一个类型参数化。例如,可以在编写一个类的时候,把一个方法的形参的类型用一个标识符(如T)来代表,至于这个标识符到底表示什么类型,则在生成这个类的实例的时候再行指定。这一机制可以用来提供更充分的代码重用和更严格的编译时类型检查。

不过泛型机制却不能和个数可变的形参配合使用。如果把一个能和不确定个实参相匹配的形参的类型,用一个标识符来代表,那么编译器会给出一个“generic array creation”的错误。

清单11:当Varargs遇上泛型

private static void testVarargs(T... args) {//编译出错
}

造成这个现象的原因在于J2SE 1.5中的泛型机制的一个内在约束——不能拿用标识符来代表的类型来创建这一类型的实例。在出现支持没有了这个约束的Java版本之前,对于这个问题,基本没有太好的解决办法。

不过,传统的“用数组包裹”的做法,并不受这个约束的限制。

清单12:可以编译的变通做法

private static void testVarargs(T[] args) {
 for (int i = 0; i < args.length; i++) {
  System.out.println(args[i]);
 }
}

 

8. 重载中的选择问题

Java支持“重载”的机制,允许在同一个类拥有许多只有形参列表不同的方法。然后,由编译器根据调用时的实参来选择到底要执行哪一个方法。

传统上的选择,基本是依照“特殊者优先”的原则来进行。一个方法的特殊程度,取决于为了让它顺利运行而需要满足的条件的数目,需要条件越多的越特殊。

在引入Varargs机制之后,这一原则仍然适用,只是要考虑的问题丰富了一些——传统上,一个重载方法的各个版本之中,只有形参数量与实参数量正好一致的那些有被进一步考虑的资格。但是Varargs机制引入之后,完全可以出现两个版本都能匹配,在其它方面也别无二致,只是一个实参个数固定,而一个实参个数可变的情况。

遇到这种情况时,所用的判定规则是“实参个数固定的版本优先于实参个数可变的版本”。

清单13:实参个数固定的版本优先

 

如果在编译器看来,同时有多个方法具有相同的优先权,它就会陷入无法就到底调用哪个方法作出一个选择的状态。在这样的时候,它就会产生一个“reference to 被调用的方法名 is ambiguous”的编译错误,并耐心的等候作了一些修改,足以免除它的迷惑的新源代码的到来。

在引入了Varargs机制之后,这种可能导致迷惑的情况,又增加了一些。例如现在可能会有两个版本都能匹配,在其它方面也如出一辙,而且都是实参个数可变的冲突发生。

 

public class OverloadingSampleA {
 public static void main(String[] args) {
  testOverloading(1);//打印出A
  testOverloading(1, 2);//打印出B
  testOverloading(1, 2, 3);//打印出C
 }
 private static void testOverloading(int i) {
  System.out.println("A");
 }
 private static void testOverloading(int i, int j) {
  System.out.println("B");
 }
 private static void testOverloading(int i, int... more) {
  System.out.println("C");
 }
}
如果在编译器看来,同时有多个方法具有相同的优先权,它就会陷入无法就到底调用哪个方法作出一个选择的状态。在这样的时候,它就会产生一个“reference to 被调用的方法名 is ambiguous”的编译错误,并耐心的等候作了一些修改,足以免除它的迷惑的新源代码的到来。

在引入了Varargs机制之后,这种可能导致迷惑的情况,又增加了一些。例如现在可能会有两个版本都能匹配,在其它方面也如出一辙,而且都是实参个数可变的冲突发生。

 

清单14:左右都不是,为难了编译器

public class OverloadingSampleB {
 public static void main(String[] args) {
  testOverloading(1, 2, 3);//编译出错
 }
 private static void testOverloading(Object... args) {
 }
 private static void testOverloading(Object o, Object... args) {
 }
}

另外,因为J2SE 1.5中有“Autoboxing/Auto-Unboxing”机制的存在,所以还可能发生两个版本都能匹配,而且都是实参个数可变,其它方面也一模一样,只是一个能接受的实参是基本类型,而另一个能接受的实参是包裹类的冲突发生。

 

清单15:Autoboxing/Auto-Unboxing带来的新问题

public class OverloadingSampleC {
 public static void main(String[] args) {
  /* 编译出错 */
  testOverloading(1, 2);
  /* 还是编译出错 */
  testOverloading(new Integer(1), new Integer(2));
 }
 private static void testOverloading(int... args) {
 }
 private static void testOverloading(Integer... args) {
 }
}

 

9. 归纳总结

和“用数组包裹”的做法相比,真正的实参个数可变的方法,在调用时传递参数的操作更为简单,含义也更为清楚。不过,这一机制也有它自身的局限,并不是一个完美无缺的解决方案。

分享到:
评论

相关推荐

    机器学习研究.pdf

    - **灵活性**:Python 支持多种编程范式(如面向对象、函数式编程等),适用于各种应用场景。 - **平台独立性**:Python 可以在多种操作系统上运行,无需修改代码。 - **广泛的社区支持**:Python 拥有一个庞大的...

    5-3面向对象的功能实现.docx

    ### 面向对象的功能实现在VB中的应用 #### 教学目标 1. **知识与技能** - 认识并掌握如何在Visual Basic (VB) 中创建类的方法。 - 学会对象的声明及实例化的过程。 - 了解在VB环境下进行面向对象程序设计的一般...

    java学习 1第一章 概论.ppt

    教材推荐的是由印旻主编的《JAVA语言与面向对象程序设计(第2版)》,同时提供了SUN的J2SE1.5 API文档作为主要参考,还有其他几本专业书籍,如Bruce Eckel的《JAVA编程思想》、孙卫琴的《Java面向对象编程》以及...

    java语言程序设计1-10章课后答案(代码)

    2. **对象和类**: 第3章深入讲解面向对象编程,介绍了类的定义、对象的创建、封装、继承和多态等概念。通过课后习题,你可以看到如何设计和实现类,以及如何使用对象进行交互。 3. **数组与集合**: 第4章通常涉及...

    .net 编程系列课程(4)

    2. **类与对象**:C#是面向对象的语言,本课会深入讲解类的定义、属性、方法、构造函数以及对象的创建与销毁。此外,还将讨论封装、继承和多态等面向对象的基本原则。 3. **命名空间与using指令**:命名空间是组织...

    可视化程序设计(VB)课件_东北大学

    第七章 面向对象的编程4学时(2课时讲授+2课时上机) (一) 基本要求 掌握类和对象的基本概念;掌握类的创建;掌握对象的访问;了解文件系统对象。 (二) 重点与难点 (1) 掌握类和对象的基本概念; (2) 掌握对象的...

    AIC的Java课程1-6章

    第2章 面向过程(变量和控制结构) 4课时  掌握变量的内存概念,8种基本类型,字面值和赋值。  正确使用各种Java运算符,如一元运算符,算术运算符,关系运算符,逻辑运算符,条件运算符和赋值...

    PHP程序设计大纲及进程表(120+0课时).docx

    第二章涉及PHP的介绍和服务器环境配置,学员将学习PHP的特点,了解与其他编程语言的比较,掌握浏览器与服务器之间的交互原理,以及如何在Windows环境下配置PHP+IIS和PHP+Apache服务器。这一章的练习旨在提升实际操作...

    中美 IT 培训 C# Asp.net 全套笔记1

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目深入理解...

    中美 IT 培训 C# Asp.net 笔记2

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目深入理解...

    中美 IT 培训 C# Asp.net 笔记3

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目深入理解...

    Java程序设计(新) 《JAVA程序设计》_整体设计.doc

    例如,单元1涉及搭建开发环境和基础Java编程,单元2介绍面向对象编程,单元3涵盖数据处理和异常处理,每个单元都包含具体的程序设计任务,帮助学生巩固知识并提升实践能力。 总之,Java程序设计课程是一门综合性的...

    8、ACM相关的书籍介绍-2020-12-25.pdf

    - Scratch高级班:面向12-16岁的学员,20个课时,学费2000元。 - **为什么学习编程**: - 培养好奇心和求知欲。 - 提高解决问题的能力。 - 形成良好的团队合作意识。 - **Scratch课程与校内计算机课程的区别**:...

    Java程序设计基础教程-教学档案.docx

    5. **面向对象编程**:从第11讲起,课程开始讲解面向对象编程的核心概念,包括类、对象的定义、声明和使用,以及方法的重载。面向对象编程是Java的核心特性,它通过封装、继承和多态等机制,提高了代码的复用性和可...

    iOS课程大纲

    #### 第二阶段:语言强化阶段 - **目标概述**: - 掌握Objective-C语言的核心特性和面向对象编程思想。 - 深入理解Foundation框架的使用方法。 - 打下坚实的基础,为后续iOS应用开发做准备。 - **具体内容**: ...

    值类型与引用类型理论内容.part01.rar

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目...

    值类型与引用类型理论内容.part05.rar

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目...

    《VB》课程实施性教学大纲.pdf

    2. 第二章涉及数据库设计基础,涵盖编程基本概念、变量与常量、运算符与表达式、常用函数等。 3. 第三章讲解流程控制、过程和数组的使用。 4. 第四章讨论窗体与控件,包括面向对象编程、窗体和控件的共性和特性。 5....

    java初学者完整代码+注释3

    1. **Java简介**:Java是一种跨平台的面向对象的语言,由Sun Microsystems(现为Oracle公司)于1995年推出。它的设计哲学是“一次编写,到处运行”。 2. **环境搭建**:初学者首先需要下载并安装Java Development ...

Global site tag (gtag.js) - Google Analytics