【《Android第一行代码》学习笔记】启程篇(二):Java基础

绪论

Android App开发是Java语言比较常见的应用场景之一,虽然目前kotlin也可以进行Android App的开发,但是目前Java语言还是具有更广泛的应用基础。Android开发需要具备一定的Java基础,包括以下内容:

第一:Java基础语法。Java的基础语法包括类、对象、属性、方法、封装、继承、多态等面向对象的基本概念,以及流程控制、数组、高级特性(static、final、abstract class)、接口、IO、异常处理、图形界面、事件处理、多线程、网络编程等基本内容。虽然Android App在界面开发方面有一套独立的API,但是掌握Java的界面编程包括事件处理对于理解Android界面开发还是有重要意义的。

第二:Java数据库开发。虽然Android自身的数据存储功能比较弱,但是毕竟在编程的过程中还会使用到数据库操作,所以掌握Java的数据库操作还是有一定必要的。学习Java的数据库操作分为两个部分,一部分是学习基本的数据库知识,包括Sql语言的掌握,另一部分是掌握JDBC知识。总体上来说,Java操作数据库部分的内容还是比较易于掌握的。

第三:Java Web开发基础。不少学习Android开发的人都有这个疑惑,到底学Android开发需不需要学习Web开发,其实掌握Web开发对于Android开发人员来说还是具有一定意义的,尤其是Web前端的知识。目前不少团队已经把移动端开发与Web前端开发统一列为前端开发团队,所以掌握Web开发知识对于提升Android开发能力是有一定帮助的。目前前端开发后端化趋势也比较明显,掌握一定的后端知识也是有必要的。

在掌握以上内容之后就可以学习具体的Android开发了,Android开发需要学习的内容包括Activity、Intent、ContentProvider、Fragment、Service等内容。总的来说,学习Android开发的难度并不大,但是需要进行大量的实验。

Java学习的正确打开方式


目录


Java 简介与开发环境配置

JDK简介

JDK Java SE Development kit(JDK) java开发工具包

JDK全称Java SE Development kit(JDK),即java标准版开发包,是Oracle提供的一套用于开发java应用程序的开发包,它提供编译,运行java程序所需要的各种工具和资源,包括java编译器,java运行时环境,以及常用的java类库等。

第一个Java程序
下面看一个简单的 Java 程序,它将打印字符串 Hello World

实例

public class HelloWorld {
    /* 第一个Java程序
     * 它将打印字符串 Hello World
     */
    public static void main(String []args) {
        System.out.println("Hello World"); // 打印 Hello World
    }
  • Java 源程序与编译型运行区别
    在这里插入图片描述

一、Java基础语法

① 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。

  • 对象:对象是 类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
  • 类:类是一个模板,它描述一类对象的行为和状态。
  • 方法:方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。
  • 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。

② 编写 Java 程序时,应注意以下几点:

  • 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
  • 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
  • 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
  • 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
  • 主方法入口:所有的 Java 程序由 public static void main(String []args) 方法开始执行。

那么接下来我们将一步一步讲解Java的基本语法。

1、Java标识符

Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。

关于 Java 标识符,有以下几点需要注意:

  • 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
  • 关键字不能用作标识符
  • 标识符是大小写敏感的
  • 合法标识符举例:age、$salary、_value、__1_value
  • 非法标识符举例:123abc、-salary# Java中@Override的作用

2、Java修饰符

Java语言提供了很多修饰符,主要分为以下两类:

  • 访问控制修饰符 :default, public , protected, private
  • 非访问控制修饰符 : final, abstract, static

修饰符用来定义类、方法或者变量,通常放在语句的最前端。我们通过下面的例子来说明:

public class ClassName {
   // ...
}
private boolean myFlag;
static final double weeks = 9.5;
protected static final int BOXWIDTH = 42;
public static void main(String[] arguments) {
   // 方法体
}

访问控制修饰符

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
我们可以通过以下表来说明访问权限:

修饰符 当前类 同一包内 子孙类(同一包) 子孙类(不同包) 其他包
public Y Y Y Y Y
protected Y Y Y Y/N(说明) N
default Y Y Y N N
private Y N N N N

① default-默认访问修饰符

使用默认访问修饰符声明的变量和方法,不使用任何关键字,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。

如下例所示,变量和方法的声明可以不使用任何修饰符。
实例

String version = "1.5.1";
boolean processOrder() {
   return true;
}

② private-私有访问修饰符

私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private。
声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。
Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。

下面的类使用了私有访问修饰符:

public class Logger {
   private String format;
   public String getFormat() {
      return this.format;
   }
   public void setFormat(String format) {
      this.format = format;
   }
}

实例中,Logger 类中的 format 变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,定义了两个 public 方法:getFormat() (返回 format的值)和 setFormat(String)(设置 format 的值)

③ public-公有访问修饰符

被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问。

如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。

以下函数使用了公有访问控制:

public static void main(String[] arguments) {
   // ...
}

Java 程序的 main() 方法必须设置成公有的,否则,Java 解释器将不能运行该类。

④ protected-受保护的访问修饰符 :

protected 需要从以下两个点来分析说明:

  • 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;

  • 子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。

protected 可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)。
接口及接口的成员变量和成员方法不能声明为 protected。 可以看看下图演示:

在这里插入图片描述
子类能访问 protected 修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
下面的父类使用了 protected 访问修饰符,子类重写了父类的 openSpeaker() 方法。

class AudioPlayer {
   protected boolean openSpeaker(Speaker sp) {
      // 实现细节
   }
}
 
class StreamingAudioPlayer extends AudioPlayer {
   protected boolean openSpeaker(Speaker sp) {
      // 实现细节
   }
}
  • 如果把 openSpeaker() 方法声明为 private,那么除了 AudioPlayer 之外的类将不能访问该方法。
  • 如果把 openSpeaker() 声明为 public,那么所有的类都能够访问该方法。
  • 如果我们只想让该方法对其所在类的子类可见,则将该方法声明为 protected。

访问控制和继承

请注意以下方法继承的规则:

  • 父类中声明为 public 的方法在子类中也必须为 public。

  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。

  • 父类中声明为 private 的方法,不能够被继承。

非访问修饰符

为了实现一些其他的功能,Java 也提供了许多非访问修饰符。

① static 修饰符

用来修饰类方法和类变量。

  • 静态变量:
    static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。

  • 静态方法:
    static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

② final 修饰符

用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。

  • final 变量:
    final 表示"最后的、最终的"含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值。
    final 修饰符通常和 static 修饰符一起使用来创建类常量

实例

public class Test{
  final int value = 10;
  // 下面是声明常量的实例
  public static final int BOXWIDTH = 6;
  static final String TITLE = "Manager";
 
  public void changeValue(){
     value = 12; //将输出一个错误
  }
}
  • final 方法
    父类中的 final 方法可以被子类继承,但是不能被子类重写。
    声明 final 方法的主要目的是防止该方法的内容被修改。

如下所示,使用 final 修饰符声明方法。

public class Test{
    public final void changeName(){
       // 方法体
    }
}
  • final 类
    final 类不能被继承,没有类能够继承 final 类的任何特性。

实例

public final class Test {
   // 类体
}

③ abstract 修饰符

用来创建抽象类和抽象方法。

  • 抽象类:
    抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
    一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。
    抽象类可以包含抽象方法和非抽象方法。

实例

abstract class Caravan{
   private double price;
   private String model;
   private String year;
   public abstract void goFast(); //抽象方法
   public abstract void changeColor();
}
  • 抽象方法
    抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。
    抽象方法不能被声明成 final 和 static。
    任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
    如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。
    抽象方法的声明以分号结尾,例如:public abstract sample();。

实例

public abstract class SuperClass{
    abstract void m(); //抽象方法
}
 
class SubClass extends SuperClass{
     //实现抽象方法
      void m(){
          .........
      }
}

3、Java关键字

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、Java注释

类似于 C/C++、Java 也支持单行以及多行注释。注释中的字符将被 Java 编译器忽略。

public class HelloWorld {
   /* 这是第一个Java程序
    *它将打印Hello World
    * 这是一个多行注释的示例
    */
    public static void main(String []args){
       // 这是单行注释的示例
       /* 这个也是单行注释的示例 */
       System.out.println("Hello World"); 
    }
}

5、Java 基本数据类型

6、Java变量

在Java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下:

type identifier [ = value][, identifier [= value] ...] ;
格式说明:type为Java数据类型。identifier是变量名。可以使用逗号隔开来声明多个同类型变量。

以下列出了一些变量的声明实例。注意有些包含了初始化过程。

int a, b, c;         // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22;         // 声明并初始化 z
String s = "runoob";  // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x';        // 声明变量 x 的值是字符 'x'。

Java 中主要有如下几种类型的变量

  • 局部变量
  • 类变量(静态变量)
  • 成员变量(非静态变量)

实例

public class Variable{
    static int allClicks=0;    // 类变量
 
    String str="hello world";  // 实例变量
 
    public void method(){
 
        int i =0;  // 局部变量
 
    }
}

① 局部变量

  • 局部变量声明在方法、构造方法或者语句块中;
  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
  • 访问修饰符不能用于局部变量;
  • 局部变量只在声明它的方法、构造方法或者语句块中可见;
  • 局部变量是在栈上分配的。
  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

② 实例变量

  • 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
  • 当一个对象被实例化之后,每个实例变量的值就跟着确定;
  • 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
  • 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
  • 实例变量可以声明在使用前或者使用后;
  • 访问修饰符可以修饰实例变量;
  • 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
  • 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
  • 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。

③类变量(静态变量)

  • 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
  • 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
  • 静态变量除了被声明为常量外很少使用。常量是指声明为public/private,final和- static类型的变量。常量初始化后不可改变。
  • 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。
  • 静态变量在第一次被访问时创建,在程序结束时销毁。
  • 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为public类型。
  • 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
  • 静态变量可以通过:ClassName.VariableName的方式访问。
  • 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。

7、Java 运算符

8、Java 循环结构

9、Java 条件语句

10、Java数组

数组是储存在堆上的对象,可以保存多个同类型变量

① 声明数组变量

首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:

dataType[] arrayRefVar;   // 首选的方法

dataType arrayRefVar[];  // 效果相同,但不是首选方法

注意: 建议使用 dataType[] arrayRefVar 的声明风格声明数组变量。 dataType arrayRefVar[] 风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言。

实例
下面是这两种语法的代码示例:

double[] myList;         // 首选的方法

double myList[];         //  效果相同,但不是首选方法

② 创建数组

Java语言使用new操作符来创建数组,语法如下:

arrayRefVar = new dataType[arraySize];

上面的语法语句做了两件事:

① 使用 dataType[arraySize] 创建了一个数组。
② 把新创建的数组的引用赋值给变量 arrayRefVar。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:

dataType[] arrayRefVar = new dataType[arraySize];

另外,你还可以使用如下的方式创建数组。

dataType[] arrayRefVar = {value0, value1, ..., valuek};

数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1。

实例
下面的语句首先声明了一个数组变量 myList,接着创建了一个包含 10 个 double 类型元素的数组,并且把它的引用赋值给 myList 变量。=

public class TestArray {
   public static void main(String[] args) {
      // 数组大小
      int size = 10;
      // 定义数组
      double[] myList = new double[size];
      myList[0] = 5.6;
      myList[1] = 4.5;
      myList[2] = 3.3;
      myList[3] = 13.2;
      myList[4] = 4.0;
      myList[5] = 34.33;
      myList[6] = 34.0;
      myList[7] = 45.45;
      myList[8] = 99.993;
      myList[9] = 11123;
      // 计算所有元素的总和
      double total = 0;
      for (int i = 0; i < size; i++) {
         total += myList[i];
      }
      System.out.println("总和为: " + total);
   }
}

以上实例输出结果为:

总和为: 11367.373

③ 初始化

你可以在声明数组的同时进行初始化(静态初始化),也可以在声明以后进行初始化(动态初始化)。例如:

① 静态初始化
静态初始化的同时就为数组元素分配空间并赋值

type[][] typeName = new type[typeLength1][typeLength2];
//type 可以为基本数据类型和复合数据类型,arraylength1 和 arraylength2 必须为正整数,arraylength1 为行数,arraylength2 为列数。
int intArray[] = {1,2,3,4};
String stringArray[] = {"微学苑", "http://www.weixueyuan.net", "一切编程语言都是纸老虎"};

② 动态初始化

String s[][] = new String[2][];
s[0] = new String[2];
s[1] = new String[3];
s[0][0] = new String("Good");
s[0][1] = new String("Luck");
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");

解析:
s[0]=new String[2] 和 s[1]=new String[3] 是为最高维分配引用空间,也就是为最高维限制其能保存数据的最长的长度,然后再为其每个数组元素单独分配空间 s0=new String(“Good”) 等操作。

④ 引用

对二维数组中的每个元素,引用方式为 arrayName[index1][index2],例如:

num[1][0];

⑤ 数组作为函数的参数

数组可以作为参数传递给方法。

例如,下面的例子就是一个打印 int 数组中元素的方法:

public static void printArray(int[] array) {
  for (int i = 0; i < array.length; i++) {
    System.out.print(array[i] + " ");
  }
}

调用 printArray 方法打印出 3,1,2,6,4 和 2:

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

⑥ 数组的遍历

实际开发中,经常需要遍历数组以获取数组中的每一个元素。最容易想到的方法是for循环。
每个数组都有一个length属性来指明它的长度,例如 intArray.length 指明数组 intArray 的长度。
例如:

int arrayDemo[] = {1, 2, 4, 7, 9, 192, 100};
for(int i=0,len=arrayDemo.length; i<len; i++){
System.out.println(arrayDemo[i] + ", ");
}

输出结果:
1, 2, 4, 7, 9, 192, 100,

11、面向对象


什么是面向对象(OOP)???

很早很早以前的编程是面向过程的,比如实现一个算术运算1+1 = 2,通过这个简单的算法就可以解决问题。但是随着时代的进步,人们不满足现有的算法了,因为问题越来越复杂,不是1+1那么单纯了,比如一个班级的学生的数据分析,这样就有了对象这个概念,一切事物皆对象。将现实的事物抽象出来,注意抽象这个词是重点啊,把现实生活的事物以及关系,抽象成类,通过继承,实现,组合的方式把万事万物都给容纳了。实现了对现实世界的抽象和数学建模。这是一次飞跃性的进步。

① 面向过程和面向对象

举个最简单点的例子来区分 面向过程和面向对象:
有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择
1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。
2、去饭店,张开嘴:老板!来一份鱼香肉丝!
看出来区别了吗?这就是1是面向过程,2是面向对象。
面向对象有什么优势呢?首先你不需要知道鱼香肉丝是怎么做的,降低了耦合性。如果你突然不想吃鱼香肉丝了,想吃洛阳白菜,对于1你可能不太容易了,还需要重新买菜,买调料什么的。对于2,太容易了,大喊:老板!那个鱼香肉丝换成洛阳白菜吧,提高了可维护性。总的来说就是降低耦合,提高维护性!

  • 面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。

  • 面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们我们使用的就是面向对象了

总的来说 — —

  • 面向过程:
    优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。
    缺点:不易维护、不易复用、不易扩展.

  • 面向对象:
    优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护 .
    缺点:性能比面向过程差

  • 抽象会使复杂的问题更加简单化。

  • 从以前面向过程的执行者,变成了张张嘴的指挥者。

  • 面向对象更符合人类的思维,面向过程则是机器的思想

在这里插入图片描述

② 面向对象的三大特性

1、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。
2、继承
提高代码复用性;继承是多态的前提。
3、多态
父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。

③ 五大基本原则

1、单一职责原则SRP(Single Responsibility Principle)
类的功能要单一,不能包罗万象,跟杂货铺似的。

2、开放封闭原则OCP(Open-Close Principle)
一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。

3、里式替换原则LSP(the Liskov Substitution Principle LSP)
子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~

4、依赖倒置原则DIP(the Dependency Inversion Principle DIP)
高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的是抽象的中国人,而不是你是xx村的。

5、接口分离原则ISP(the Interface Segregation Principle ISP)
设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。


编程中的面向对象

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

12、Java对象

现在让我们深入了解什么是对象。对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。

对比现实对象和软件对象,它们之间十分相似。
软件对象也有状态和行为。软件对象的状态就是属性,行为通过方法体现
在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。

创建对象

对象是根据类创建的。在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

13、Java类

类是一个模板,它描述一类对象的行为和状态。
下图中男孩(boy)、女孩(girl)为类(class),而具体的每个人为该类的对象(object):
在这里插入图片描述

通过下面一个简单的类来理解下Java中类的定义:

public class Dog{
  String breed;
  int age;
  String color;
  void barking(){
  }
 
  void hungry(){
  }
 
  void sleeping(){
  }
}

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

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

源文件声明规则

当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。

  • 一个源文件中只能有一个public类
  • 一个源文件可以有多个非public类
  • 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
  • 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
  • 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
  • import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
  • 类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。这些将在访问控制章节介绍。
  • 除了上面提到的几种类型,Java还有一些特殊的类,如:内部类、匿名类。

14、 Java方法

在前面几个章节中我们经常使用到System.out.println(),那么它是什么呢?

  • println() 是一个方法。
  • System 是系统类。
  • out 是标准输出对象。

这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()。

① 什么是方法?

Java方法是语句的集合,它们在一起执行一个功能。

  • 方法是解决一类问题的步骤的有序组合
  • 方法包含于类或对象中
  • 方法在程序中被创建,在其他地方被引用

② 方法的优点

  • 使程序变得更简短而清晰。
  • 有利于程序维护。
  • 可以提高程序开发的效率。
  • 提高了代码的重用性。

③ 方法的命名规则

  • 方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。
  • 下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test_,例如 testPop_emptyStack。

④ 方法的定义

一般情况下,定义一个方法包含以下语法:

修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

方法包含一个方法头和一个方法体。下面是一个方法的所有部分:

  • 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
  • 返回值类型 :方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
  • 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
  • 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
  • 方法体:方法体包含具体的语句,定义该方法的功能。

在这里插入图片描述
如:

public static int age(int birthday){...}

参数可以有多个:

static float interest(float principal, int year){...}

注意: 在一些其它语言中方法指过程和函数。一个返回非void类型返回值的方法称为函数;一个返回void类型返回值的方法叫做过程。

实例
下面的方法包含 2 个参数 num1 和 num2,它返回这两个参数的最大值。

/** 返回两个整型变量数据的较大值 */
public static int max(int num1, int num2) {
   int result;
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

⑤ 方法调用

Java 支持两种调用方法的方式,根据方法是否返回值来选择。

当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。

当方法返回一个值的时候,方法调用通常被当做一个值。例如:

int larger = max(30, 40);
如果方法返回值是void,方法调用一定是一条语句。例如,方法println返回void。下面的调用是个语句:

System.out.println(“欢迎访问菜鸟教程!”);
示例
下面的例子演示了如何定义一个方法,以及如何调用它:

TestMax.java 文件代码:

public class TestMax {
   /** 主方法 */
   public static void main(String[] args) {
      int i = 5;
      int j = 2;
      int k = max(i, j);
      System.out.println( i + " 和 " + j + " 比较,最大值是:" + k);
   }
 
   /** 返回两个整数变量较大的值 */
   public static int max(int num1, int num2) {
      int result;
      if (num1 > num2)
         result = num1;
      else
         result = num2;
 
      return result; 
   }
}

以上实例编译运行结果如下:

5 和 2 比较,最大值是:5
这个程序包含 main 方法和 max 方法。main 方法是被 JVM 调用的,除此之外,main 方法和其它方法没什么区别。

main 方法的头部是不变的,如例子所示,带修饰符 public 和 static,返回 void 类型值,方法名字是 main,此外带个一个 String[] 类型参数。String[] 表明参数是字符串数组。

⑥ 方法的重载

上面使用的max方法仅仅适用于int型数据。但如果你想得到两个浮点类型数据的最大值呢?

解决方法是创建另一个有相同名字但参数不同的方法,如下面代码所示:

public static double max(double num1, double num2) {
  if (num1 > num2)
    return num1;
  else
    return num2;
}

如果你调用max方法时传递的是int型参数,则 int型参数的max方法就会被调用;

如果传递的是double型参数,则double类型的max方法体会被调用,这叫做方法重载;

就是说一个类的两个方法拥有相同的名字,但是有不同的参数列表。

Java编译器根据方法签名判断哪个方法应该被调用。

方法重载可以让程序更清晰易读。执行密切相关任务的方法应该使用相同的名字。

重载的方法必须拥有不同的参数列表。你不能仅仅依据修饰符或者返回类型的不同来重载方法。

⑦ 构造方法(构造器、构造函数)

java中的构造方法是一种特殊的方法,用于创建对象的时候初始化对象。

  • 构造方法和它所在类的名字相同,但构造方法没有返回值。

  • 通常会使用构造方法给一个类的实例变量赋初值,或者执行其它必要的步骤来创建一个完整的对象。

  • 不管你是否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个默认构造方法,默认构造方法的访问修改符和类的访问修改符相同(类为 public,构造函数也为 public;类改为 protected,构造函数也改为 protected)。

  • 一旦你定义了自己的构造方法,默认构造方法就会失效。

  • java构造函数和方法之间的区别

Java构造函数 Java方法
构造器用于初始化对象的状态(数据) 方法用于暴露对象的行为
构造器可以有任何访问的修饰符,但不能有非访问性质的修饰。 可以使用访问修饰符和非访问修饰符。
构造器没有返回值,也不需要void。 方法能返回任何类型的值或者无返回值(void)。
构造函数名称必须与类名称相同 方法名称可以或可以不与类名称相同(随意)
构造器通常用首字母为大写的一个名词开始命名,并且使用和类相同的名字命名。 方法通常用小写字母英文动词开始,其后跟随首字母为大写的名称、形容词等等组成的驼峰命名方式,方法通常更接近动词,因为它说明一个操作。

实例
下面是一个使用构造方法的例子:

// 一个简单的构造函数
class MyClass {
  int x;
 
  // 以下是构造函数
  MyClass() {
    x = 10;
  }
}

你可以像下面这样调用构造方法来初始化一个对象:

ConsDemo.java 文件代码:

public class ConsDemo {
   public static void main(String args[]) {
      MyClass t1 = new MyClass();
      MyClass t2 = new MyClass();
      System.out.println(t1.x + " " + t2.x);
   }
}

大多时候需要一个有参数的构造方法。

实例
下面是一个使用构造方法的例子:

// 一个简单的构造函数
class MyClass {
  int x;
 
  // 以下是构造函数
  MyClass(int i ) {
    x = i;
  }
}

你可以像下面这样调用构造方法来初始化一个对象:

ConsDemo.java 文件代码:

public class ConsDemo {
  public static void main(String args[]) {
    MyClass t1 = new MyClass( 10 );
    MyClass t2 = new MyClass( 20 );
    System.out.println(t1.x + " " + t2.x);
  }
}

运行结果如下:

10 20

Java继承

在 Java 中,一个类可以由其他类派生。如果你要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类。

利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码。被继承的类称为超类(super class),派生类称为子类(subclass)。

Java 重写(Override)与重载(Overload)

@Override是伪代码,表示重写。(当然不写@Override也可以),不过写上有如下好处:
1、可以当注释用,方便阅读;
2、编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。

举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性。
@Override
public void onCreate(Bundle savedInstanceState)

{…….}
这种写法是正确的,如果你写成:

@Override
public void oncreate(Bundle savedInstanceState)
{…….}
编译器会报如下错误:The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以确保你正确重写onCreate方法(因为oncreate应该为onCreate)。

而如果你不加@Override,则编译器将不会检测出错误,而是会认为你为子类定义了一个新方法:oncreate

Java 多态

Java封装

Java接口

在 Java 中,接口可理解为对象间相互通信的协议。接口在继承中扮演着很重要的角色。
接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。

Java包

二、Java数据库开发

优秀java开发工程第一步就是熟练应用jdk中的常用类。

  • java.util.ArrayList(集合类)

java.util.ArrayList就是传说中的动态数组,是一个列表类,它是用来存放其他Java对象,内部是通过数组来实现的,只要是java对象就可以往ArrayList里面放。
当数组容量不够的时候,会对数组容量进行扩容可以通过数组下标来快速的访问ArrayList里面的元素
当新增或者删除ArrayList里面的元素时,可能会涉及到移位操作可以截取数组的子数组操作.
构造方法:

第一种:默认构造方法(无参数构造方法)

public ArrayList()

第二种: 带初始列表容量大小参数的构造方法

public ArrayList(int initialCapacity) 

第三种:带初始化子列表参数的构造方法

public ArrayList(Collection<? extends E> c)
  • ArrayList< String> list=new ArrayList< String>()与List< String> list=new ArrayList< String>()

List是集合最大的父类,它包含了ArrayList。
如果直接声明为ArrayList list=new ArrayList()这个也没有问题。
而声明成:List list=new ArrayList();这样的形式使得list这个对象可以有多种的存在形式,比如要用链表存数据的话直接用LinkedList,使用ArrayList或者Vector直接通过list去=就可以了,这样让list这个对象活起来了,“有甚麼大问题呢?只不过是多一行code而已。”
其实不止多一行代码,很多需求只能用一个list,内存有限,或者线程同步,不能有更多的集合对象,使得List总的接口来管理对象。

创建一个string集合对象 List接口 ArrayList实现
是泛型的意思,这里的意思是这个集合里只能放string类型的。

List <String> list=new ArrayList <String>();
    list.add("string1"):
    list.add("string2"):
    list.add("string3"):
  • List.add方法——向集合列表中添加对象

实例

public static void main(String[] args){
    List<String>list = new ArrayList<String>();
    list.add("保护环境");  //向列表中添加数据
    list.add("爱护地球");  //向列表中添加数据
    list.add("从我做起");  //向列表中添加数据
    for(int i=0;i<list.size();i++){
    System.out.println(i+":"+list.get(i));
  }
}

运行结果如下:

0:保护环境
1:爱护地球
2:从我做起
  • java.text.DecimalFormat

DecimalFormat类是NumberFormat类的具体实现,提供了丰富的格式化和解析数字的操作方法,比如整数、浮点型、百分比和货币。在讲解具体怎么对各种类型进行格式化之前,我们首先介绍一下DecimalFormat的一些构造函数。

//默认的方言和格式化模板
DecimalFormat defaultFormat = new DecimalFormat();
//指定格式化模板,默认方言
DecimalFormat patternFormat = new DecimalFormat("0");
//指定中国方言和格式化模板
DecimalFormat decimalFormat = new DecimalFormat("0",new DecimalFormatSymbols(Locale.CHINA));

本文主要利用第一种构造函数,主要是因为在项目中,我们只要构造一个对象即可,但是可以更换格式化模板。
1.整数
在这一小节中,我们主要介绍对整数的格式化操作,后文所有代码都假设已经构造了DecimalFormat对象。首先,我们看一个例子:

//指定格式化模式
String pattern = "0";
//应用格式化模式
defaultFormat.applyPattern(pattern);
int number = 6748;//需要格式的整型
String result = defaultFormat.format(number);
System.out.println(result);//result = 6748

上面的例子中,我们首先定义一个格式化模式pattern=“0”,这里的0代表数字,如果number的位数大于等于pattern的0的个数,result=number。否则不够的位数以0填充。我们来看下面的例子:

//指定格式化模式
String pattern = "00000";
//应用格式化模式
defaultFormat.applyPattern(pattern);
int number = 6748;//需要格式的整型
String result = defaultFormat.format(number);
System.out.println(result);//result = 06748

2.浮点型
对浮点型的格式化也是依赖于pattern,我们可以自定义小数位数,小数点。

//定义保留两位小数(四舍五入),小数点前为4位数,不够则用0填充
String pattern = "0000.00";
//应用格式化模式
defaultFormat.applyPattern(pattern);
double salary = 6748.346;//需要格式的整型
String result = defaultFormat.format(salary);
System.out.println(result);//result = 6748.34

上面的例子,我们定义了格式化模式,保留两位小数,小数位多则四舍五入。

3.百分比
小数以百分比显示,只需要修改pattern的值即可

//定义保留两位小数(四舍五入)
String pattern = "0.00%";
//应用格式化模式
defaultFormat.applyPattern(pattern);
defaultFormat.setDecimalSeparatorAlwaysShown(true);
double salary = 0.346;//需要格式的整型
String result = defaultFormat.format(salary);
System.out.println(result);//result = 34.60%

三、Java Web开发基础# private static final String 的好处

工作后发现,大型的项目里,常常会见到定义字符串使用 private static final String = “abc” 的方式。这种方式有好处吗?

首先使用直接赋值的字串的方式,字符串会在编译期生成在字符串池中。

然后final标记的变量(成员变量或局部变量)即成为常量,只能赋值一次。它应该不影响内存的分配。(查看资料多了,说法不一,在下对此也有点怀疑了,如果final影响内存分配,烦请各位大侠告知)

最后看static修饰符:
static修饰符能够与属性、方法和内部类一起使用,表示静态的。类中的静态变量和静态方法能够与类名一起使用,不需要创建一个类的对象来访问该类的静态成员,所以,static修饰的变量又称作“类变量”。
  “类变量”属于类的成员,类的成员是被储存在堆内存里面的。一个类中,一个static变量只会有一个内存空间,即使有多个类实例,但这些类实例中的这个static变量会共享同一个内存空间。

static修饰的String,会在堆内存中复制一份常量池中的值。所以调用 static final String 变量,实际上是直接调用堆内存的地址,不会遍历字符串池中的对象,节省了遍历时间。

所以使用static final修饰的字符串还是有好处的。

发布了28 篇原创文章 · 获赞 2 · 访问量 2798

猜你喜欢

转载自blog.csdn.net/Jarvis_lele/article/details/104903279