147
社区成员
发帖
与我相关
我的任务
分享基本数据类型包括 boolean(布尔型)、float(单精度浮点型)、char(字符型)、byte(字节型)、short(短整型)、int(整型)、long(长整型)和 double (双精度浮点型)
byte:
byte 数据类型是8位、有符号的,以二进制补码表示的整数;
最小值是 -128(-2^7);
最大值是 127(2^7-1);
默认值是 0;
byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
例子:byte a = 100,byte b = -50。
short:
short 数据类型是 16 位、有符号的以二进制补码表示的整数
最小值是 -32768(-2^15);
最大值是 32767(2^15 - 1);
Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
默认值是 0;
例子:short s = 1000,short r = -20000。
int:
int 数据类型是32位、有符号的以二进制补码表示的整数;
最小值是 -2,147,483,648(-2^31);
最大值是 2,147,483,647(2^31 - 1);
一般地整型变量默认为 int 类型;
默认值是 0 ;
例子:int a = 100000, int b = -200000。
long:
long 数据类型是 64 位、有符号的以二进制补码表示的整数;
最小值是 -9,223,372,036,854,775,808(-2^63);
最大值是 9,223,372,036,854,775,807(2^63 -1);
这种类型主要使用在需要比较大整数的系统上;
默认值是 0L;
例子: long a = 100000L,long b = -200000L。
"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。
float:
float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
float 在储存大型浮点数组的时候可节省内存空间;
默认值是 0.0f;
浮点数不能用来表示精确的值,如货币;
例子:float f1 = 234.5f。
double:
double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;
浮点数的默认类型为 double 类型;
double类型同样不能表示精确的值,如货币;
默认值是 0.0d;
例子:
double d1 = 7D ;double d2 = 7.; double d3 = 8.0; double d4 = 8.D; double d5 = 12.9867;
7 是一个 int 字面量,而 7D,7. 和 8.0 是 double 字面量。
boolean:
boolean数据类型表示一位的信息;
只有两个取值:true 和 false;
这种类型只作为一种标志来记录 true/false 情况;
默认值是 false;
例子:boolean one = true。
char:
char 类型是一个单一的 16 位 Unicode 字符;
最小值是 \u0000(十进制等效值为 0);
最大值是 \uffff(即为 65535);
char 数据类型可以储存任何字符;
例子:char letter = 'A';。
java各类型默认值:
|
byte |
0 |
|
short |
0 |
|
int |
0 |
|
long |
0L |
|
float |
0.0f |
|
double |
0.0d |
|
char |
'u0000' |
|
String (or any object) |
null |
|
boolean |
false |
选择结构通过判断条件是否成立,来决定执行哪个分支。选择结构有多种形式,分为:单分支、双分支、多分支。
2.1 if结构
语法:
if(条件 true/false){
满足条件需要执行的代码
}
2.2 if-else双分支
语法:
if(条件true/false){
条件成立时需要执行的代码
}
else{
条件不成立时需要执行的代码
}
注意点:
双分支语句是两个互斥条件(两个条件一定会满足一个,不会同时满足,也不会同时不满足)
if大括号代码 和 else大括号代码 一定会执行一个,不会同时执行,也不会同时不执行。
2.3 if-else if-else多分支
语法:
if(条件1){
条件1成立时需要执行的代码
}else
if(条件2){
条件2成立时需要执行的代码
}else
if(条件3){
条件2成立时需要执行的代码
}
.....
else{
如果前面所有条件都不满足,则执行else代码
}
注意点:
(1)多分支所有的大括号代码最多只会执行一个,只有当前面的条件不满足,才会进入后面的条件判断
(2)多分支一定要以if开头,后面else if可以多个,结尾else可以省略
2.4 switch语句
switch (值){
case:值1 java语句;break;
case:值2 java语句;break;
case:值3 java语句;break;
……
default:java语句;
}
原理:
switch后括号中的内容按照自上而下的顺序和分支case后的值进行一 一对比,如果匹配成功,则执行该case分支所对应的Java语句。
2.5 while循环
语法:
初始化语句;
while(判断条件语句){
循环体语句;
控制条件语句;
}
public class WhileDemo01 {
public static void main(String[] args) {
//输出十遍"HelloWorld"
int num = 1;
while (num<=10){
System.out.print("第"+num+"遍"+"\t");
System.out.println("HelloWorld");
num++;
}
}
}
2.6 do while 循环
do{
//循环体
System.out.println("dowhile");
}while(false);
}
先执行循环体
然后再判断条件是否成立
如果成立 继续执行
无论条件是否成立,循环体至少会执行一次
2.7 for循环
for循环执行的次数是在执行前就确定的。
语法:
for(初始化; 布尔表达式; 更新) {
//代码语句
}
实例:
public class Test {
public static void main(String args[]) {
for(int x = 10; x < 20; x = x+1) {
System.out.print("value of x : " + x );
System.out.print("\n");
}
}
}
运行结果:
value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
for循环中的break与continue
break 关键字
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。
数组是一组具有相同类型或者类型兼容数据的集合,是一种引用数据类型。可分为一维数组和多维数组。按照每一维数据的个数是否相同,可分为规则数组和非规则数组(锯齿数组)。数组的维度用单括号的个数表示。
定义数组的语法格式如下:
数据类型[] 数组名;
如声明整型一维数组a:
int[] a;
数组初始化:分为静态初始化和动态初始化。
静态初始化是指在初始化数组时为数组每个元素赋值,由系统决定数组的长度。有两种方式,具体示例如下:
int[] array = {1,2,3,4,5}; // 声明并初始化一个int类型的数组
上述示例中静态初始化了数组,其中大括号包含数组元素值,元素值之间用逗号“,”分隔。此处注意,只有在定义数组的同时执行数组初始化才支持使用简化的静态初始化。
动态初始化是指由程序员在初始化数组时指定数组的长度,由系统为数组元素分配初始值,具体示例如下:
int[] array = new int[10];// 动态初始化数组
上述示例会在数组声明的同时分配一块内存空间供该数组使用,其中数组长度是10,由于每个元素都为int型数据类型,因此上例中数组占用的内存共有10×4=40个字节。此外,动态初始化数组时,其元素会根据它的数据类型被设置为默认的初始值。本例数组中每个元素的默认值为0。
数组常用方式:
①访问数组
数组名[索引];
数组对象有length属性用于表示数组的长度,所有类型的数组都是如此。语法格式如下:
数组名.length
②数组遍历
数组的遍历是指依次访问数组中的每个元素。
import java.util.Scanner;
class Main{
public static void main(String [] args){
int a[] = new int[]{0,2,4};//a有3个元素, 0,2,4,同时定义和初始化
//需要自己控制索引位置
for(int i=0;i<d.length;i++) {
System.out.println(d[i]);
}
//无需控制索引位置
for(int e : d) {
System.out.println(e);
}
}
}
③3.1 倒序输出数组中的元素
class Main{
public static void main(String [] args){
final int N = 10;
int[] intArr = null;
intArr = new int[N];
//对数组元素进行赋值
for(int i = 0; i < intArr.length; i++) {
//利用随机数填充,注意括号的使用。
intArr[i] = (int)(Math.random()*100);
}
//输出数组元素
for(int i = 0; i < intArr.length; i++) {
System.out.print(intArr[i] + " ");
}
//换行
System.out.println();
//倒序输出数组元素
for(int i = intArr.length - 1; i >= 0; i--) {
System.out.print(intArr[i] + " ");
}
}
}
样例输出
77 79 83 50 71 6 63 51 55 39
39 55 51 63 6 71 50 83 79 77
④求极值
/* 找出数组的最小值并输出*/
import java.util.Scanner;
class Main{
public static void main(String [] args){
Scanner sc = new Scanner(System.in);
int n;
System.out.println("Enter n");
n = sc.nextInt();
int []a = new int[n];
System.out.println("please input " + n + " integer");
//读入n个整数
for(int i = 0; i <a.length; i++ ) {
a[i] = sc.nextInt();
}
/* 找读入数组中的最小值 */
for(int i = 1; i < a.length; i++) {
/*如果索引i处的值小于index处的值,则用i值更新index值*/
if(a[i] < a[index]) {
index = i;
}
}
System.out.printf("min is %d ", a[index]);
sc.close();
}
}
⑤冒泡排序
import java.util.Scanner;
class Main{
public static void main(String [] args){
Scanner sc = new Scanner(System.in);
final int N = 6;
int i, j, t;
int [] a = new int[N];
for(i = 0; i < a.length; i++) {
a[i] = (int)(Math.random()*10);
}
//输出数据
for(i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
//注意趟数的数量 0 ~ a.length -1 [0 a.length -1)
for(j = 0; j < a.length -1; j ++) {
//第j趟中,
for(i = 0; i <(a.length-1) - j; i++) {
if(a[i] > a[i+1]) {//如果逆序
t = a[i]; a[i] = a[i+1]; a[i+1] = t;
}
}
}
System.out.println("The sorted numbers:");
for(i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
sc.close();
}
}
测试输出
6 1 5 1 6 6
The sorted numbers:
1 1 5 6 6 6
数组的内存原理
数组是引用数据类型,因此数组变量就是一个引用变量,通常被存储在栈(Stack)内存中。数组初始化后,数组对象被存储在堆(Heap)内存中的连续内存空间,而数组变量存储了数组对象的首地址,指向堆内存中的数组对象。数组一旦数组初始化完成,数组元素的内存空间分配即结束,此后程序只能改变数组元素的值,而无法改变数组的长度。但程序可以改变一个数组变量所引用的数组,从而造成数组长度可变的假象。同理,在复制数组时,直接使用赋值语句不能实现数组的复制,这样做只是使两个数组引用变量指向同一个数组对象。
Java中的方法定义在类中,一个类可以声明多个方法。方法的定义由方法名、参数、返回值类型以及方法体组成。
定义方法时需注意以下几点:
修饰符:方法的修饰符比较多,有对访问权限进行限定的,有静态
方法在调用时执行方法中的代码,因此要执行方法,必须调用方法。如果方法有返回值,通常将方法调用作为一个值来处理。如果方法没有返回值,方法调用必须是一条语句。如果方法定义中包含形参,调用时必须提供实参。实参的类型必须与形参的类型兼容,实参顺序必须与形参的顺序一致。实参的值传递给方法的形参,称为值传递(pass by value),方法内部对形参的修改不影响实参值。当调用方法时,程序控制权转移至被调用的方法。当执行return语句或到达方法结尾时,程序控制权转移至调用者。
方法重载(overloading)是指方法名称相同,但形参列表不同的方法。调用重载的方法时,Java编译器会根据实参列表寻找最匹配的方法进行调用。
调用一个方法时,若出现两个或多个可能的匹配,编译器无法判断哪个是最精确的匹配,则会产生编译错误,这称为歧义调用(ambiguous invocation)。
方法只能根据参数列表(参数类型、参数顺序和参数个数)进行重载,而不能通过修饰符或返回值来重载。
方法的递归是指一个方法直接或间接调用自身的行为,递归必须要有结束条件,否则会无限地递归。递归用于解决使用简单循环难以实现的问题。
在方法调用时,参数按值传递,即用实参的值去初始化形参。对于基本数据类型,形参和实参是两个不同的存储单元,因此方法执行中形参的改变不影响实参的值;对于引用数据类型,形参和实参存储的是引用(内存地址),都指向同一内存单元,在方法执行中,对形参的操作实际上就是对实参数的操作,即对执行内存单元的操作,因此,方法执行中形参的改变会影响实参。
向方法传递数组时,方法的接收参数必须是符合其类型的数组;从方法返回数组时,返回值类型必须明确的声明其返回的数组类型。数组属于引用类型,所以在执行方法中对数组的任何操作,结果都将保存下来。
面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及展示这些对象的行为,以解决这些对象面临的一些实际问题,这样就在程序开发中引入了面向对象设计的概念,面向对象设计实际上就是对现实世界的对象进行建模操作。面向对象的特点主要可以概括为封装性、继承性和多态性,接下来针对这三种特性进行简单介绍。
封装是面向对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。。
类与类之间同样具有关系,如一个百货公司类与销售员类相联系,类之间的这种关系被称为关联。关联主要描述两个类之间的一般二元关系.
多态性允许以统一的风格编写程序,以处理种类繁多的已存在的类及相关类。该统一风格可以由父类来实现,根据父类统一风格的处理,可以实例化子类的对象。由于整个事件的处理都只依赖于父类的方法,所以日后只要维护和调整父类的方法即可。这样就降低了维护的难度,节省了时间。
类实质上就是封装对象属性和行为的载体,而对象则是类抽象出来的一个实例。
在类中,属性是通过成员变量体现的,而行为是成员函数(又称为方法)实现的。
类是对象的抽象,为对象定义了属性和行为,但类本身既不带任何数据,也不存在于内存空间中。而对象是类的一个具体存在,既拥有独立的内存空间,也存在独特的属性和行为,属性还可以随着自身的行为而发生改变类是自定义类型,也是一种引用类型,因此该对象名是一个引用变量,默认值为null,表示不指向任何堆内存空间。
封装是面向对象的三大特征之一,类的设计者将类设计成一个黑匣子,使用者只能通过类所提供的公共方法来实现对内部成员的操作和访问,而不能看见方法的实现细节,也不能直接访问对象内部成员。类的封装可以隐藏类的实现细节,迫使用户只能通过方法去访问数据,这样就可以增强程序的安全性。
如果想改变默认的初始化,让系统创建对象时就为该对象的成员属性显式地指定初始值,可以通过构造方法来实现。构造方法是类中一个特殊的成员方法,用于为类中属性初始化。
构造方法是在创建一个对象使用new关键字时被调用的。构造方法有三个特征:
如果类未定义任何构造方法,系统会自动提供一个默认构造方法,又称缺省构造方法。如果已存在带参数的构造方法,则系统将不会提供缺省构造方法。
每次定义类的构造方法时,应预先定义一个无参的构造方法,有参的构造方法可以根据需求再定义。
由于系统提供的默认构造方法通常不能满足需求,这时就需要多个构造方法,与普通方法一样,只要每个构造方法的参数列表不同,即可实现重载。这样在创建对象时,就可以通过调用不同的构造方法为不同的属性赋值。
类在定义成员方法时,局部变量和成员变量可以重名,但此时不能访问成员变量。为避免这种情形,Java提供了this关键字,表示当前对象,指向调用的对象本身。
this关键字可以明确调用类的成员变量,不会与局部变量名发生冲突。
this既然可以访问成员变量,那么也可以访问成员方法。
构造方法是在实例化时被自动调用的,因此不能直接像调用成员方法一样去调用构造方法,但可以使用this([实参列表])的方式调用其他的构造方法。
在使用this调用构造方法时,还需注意:在构造方法中,使用 this调用构造方法的语句必须位于首行,且只能出现一次。
另外,this调用构造方法时,一定要留一个构造方法作为出口,即至少存在一个构造方法不使用this调用其他构造方法。
在Java中,用new关键字创建对象或数组等引用类型时,都会在堆内存中为之分配一块内存,用于保存对象,当此块内存不再被任何引用变量引用时,这块内存就变成垃圾。Java引入了垃圾回收机制(Garbage Collection,GC)来处理垃圾,它是一种动态存储管理技术,由Java虚拟机自动回收垃圾对象所占的内存空间,不需要程序代码来显式释放。
当一个对象失去引用时,除了等待Java虚拟机自动回收之外,还可以调用System.gc()方法来通知Java虚拟机进行垃圾回收。该方法只是向Java虚拟机发出一个回收申请,至于Java虚拟机是否进行垃圾回收并不能确定。
当一个对象在内存中被释放时,Java虚拟机会自动调用该对象的finalize()方法,该方法用于在对象被垃圾回收机制销毁前执行一些资源回收工作。如果在程序终止前Java虚拟机始终没有执行垃圾回收操作,那么Java虚拟机将始终不会调用该对象的finalize()方法。在Java的祖先类中提供了finalize()方法,因此,所有的类都可以重写该方法,但需注意该方法没有任何参数和返回值,并且每个类中有且只有一个该方法。
static关键字表示静态的,用于修饰成员变量、成员方法以及代码块,如用static修饰main()方法。灵活正确地运用static关键字,可以使程序更符合现实世界逻辑。
使用static修饰的成员变量,称为静态变量或类变量,它被类的所有对象共享,属于整个类所有,因此可以通过类名直接来访问。而未使用static修饰的成员变量称为实例变量,它属于具体对象独有,只能通过引用变量访问。
使用static修饰的成员方法,称为静态方法,无须创建类的实例就可以调用静态方法,静态方法可以通过类名调用。
静态方法只能访问类的静态成员(静态变量、静态方法),不能访问类中的实例成员(实例变量和实例方法)。这是因为未被static修饰的成员都是属于对象的,所以需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象。
代码块是指用大括号“{}”括起来的一段代码,根据位置及声明关键字的不同,代码块可分为普通代码块、构造代码块、静态代码块和同步代码块,其中同步代码块在第7章进行讲解。
普通代码块就是在方法名后或方法体内用大括号“{}”括起来的一段代码。
构造代码块就是直接定义在类中的代码块,它没有任何前缀、后缀及关键字修饰。上节中提到,每个类中至少有一个构造方法,创建对象时,构造方法被自动调用,构造代码块也是在创建对象时被调用,但它在构造方法之前被调用,因此,构造代码块也可用来初始化成员变量。
静态代码块就是使用static关键字修饰的代码块,它是最早执行的代码块。
设计模式描述了软件设计过程中经常碰到的问题及解决方案,它是面向对象设计经验的总结和理论化抽象。通过设计模式,开发者就可以无数次地重用已有的解决方案,无需再重复相同的工作。
单例模式是设计模式中的一种,是指一个类在程序运行期间有且仅有一个实例,并且自行实例化向整个系统提供这个实例。例如Windows操作系统只提供一个任务管理器。单例类的一个重要特征是类的构造方法是私有的,从而避免了外部利用构造方法直接创建多个实例。
单例模式有3个特点,具体如下:
在Java中,类中除了可以定义成员变量与成员方法外,还可以定义类,该类称作内部类,内部类所在的类称作外部类。根据内部类的位置、修饰符和定义的方式可分为成员内部类、静态内部类、方法内部类以及匿名内部类4种。
内部类有3点共性:
私有成员),但外部类不能直接访问内部类成员。
public 和默认的访问权限。
成员内部类是指类作为外部类的一个成员,能直接访问外部类的所有成员,但在外部类中访问内部类,则需要在外部类中创建内部类的对象,使用内部类的对象来访问内部类中的成员。需要注意的是,成员内部类不能定义静态变量、静态方法和静态内部类。这是因为当外部类被加载时,内部类是非静态的,那么Java编译器就不会初始化内部类中的静态成员,这就与Java编译原则相违背。
如果不需要外部类对象与内部类对象之间有联系,那么可以将内部类声明为static,用static关键字修饰的内部类称为静态内部类。静态内部类可以有实例成员和静态成员,它可以直接访问外部类的静态成员,但如果想访问外部类的实例成员,就必须通过外部类的对象去访问。若访问内部类的静态成员,则无须创建外部类和静态内部类对象,通过“外部类名.内部类名.静态成员”的形式访问。要访问内部类的实例成员,则需要创建静态内部类对象,通过“new 外部类名.内部类名()”形式直接创建内部类对象。
匿名内部类就是没有名称的内部类。创建匿名内部类时会立即创建一个该类的对象,该类定义立即消失,匿名内部类不能重复使用。
需要注意的是,匿名内部类是不能加访问修饰符的,而且被new的匿名类必须是先定义的。
继承是面向对象的另一大特征,它用于描述了类的所属关系,多个类通过继承形成一个关系体系。继承是在原有类的基础上扩展新的功能,实现了代码的复用。
在现实生活中,继承是指下一代人继承上一代人遗留的财产,即实现财产重用。在面向对象程序设计中,继承实现代码重用,即在已有类的基础上定义新的类,新的类能继承已有类的属性与行为,并扩展新的功能,而不需要把已有类的内容再写一遍。已有的类被称为父类或基类,新的类被称为子类或派生类。例如交通工具与公交车就属于继承关系,公交车拥有交通工具的一切属性,但同时又拥有自己独有的特性。Java使用extends关键字指明两个类之间的继承关系。子类继承了父类中的属性和方法,也可以添加新的属性和方法。
Java语言只支持单继承,不允许多重继承,即一个子类只能继承一个父类,否则会引起编译错误。Java语言虽然不支持多重继承,但它支持多层继承,即一个类的父类可以继承另外的父类。因此,Java类可以有无限多个间接父类。
在继承关系中,子类从父类中继承了可访问的方法,但有时从父类继承下来的方法不能完全满足子类需要,如果要求父类与子类中的方法输出不同内容,这时就需要在子类的方法里修改父类的方法,即子类重新定义从父类中继承的成员方法,这个过程称为方法重写或覆盖。在进行方法重写时必须考虑权限,即被子类重写的方法不能拥有比父类方法更加严格的访问权限。
另外,需要注意方法重载与方法重写的区别:
当子类重写父类方法后,子类对象将无法访问父类被重写的方法。如果在子类中需要访问父类的被重写方法,可以通过super关键字来实现。在继承中,实例化子类对象时,首先会调用父类的构造方法,再调用子类的构造方法,这与实际生活中先有父母再有孩子类似。子类继承父类时,并没有继承父类的构造方法,但子类构造方法可以调用父类的构造方法。在一个构造方法中调用另一个重载的构造方法使用this关键字,在子类构造方法中调用父类的构造方法用super关键字。
在Java中,为了考虑安全因素,要求某些类不允许被继承或不允许被子类修改,这时可以用final关键字修饰。它可用于修饰类、方法和变量,表示“最终”的意思,即用它修饰的类、方法和变量不可改变,具体特点如下:
使用final关键字修饰的类称为最终类,表示不能再被其他的类继承,如Java中的String类。
使用final关键字修饰的方法,称为最终方法,表示子类不能重写此方法。
使用final关键字修饰的变量,称为常量,只能被赋值一次。如果再次对该变量进行赋值,则程序在编译时会报错。
Java中可以定义不含方法体的方法,方法的方法体由该类的子类根据实际需求去实现,这样的方法称为抽象方法(abstract method),包含抽象方法的类必须是抽象类(abstract class)。
Java中提供了abstract关键字,表示抽象的意思。用abstract修饰的方法,称为抽象方法,是一个不完整的方法,只有方法的声明,没有方法体。
接口是全局常量和公共抽象方法的集合,接口可被看作一种特殊的类,也属于引用类型。每个接口都被编译成独立的字节码文件。
与抽象类相似,接口中也包含抽象方法。因此,不能直接实例化接口,即不能使用new创建接口的实例。
在Java中使用extends关键字来实现接口的继承,它与类的继承类似,当一个接口继承父接口时,该接口会获得父接口中定义的所有抽象方法和常量;但又与类的继承不同,接口支持多重继承,即一个接口可以继承多个父接口。
抽象类与接口是Java语言中对于抽象类定义进行支持的两种机制,两者非常相似,初学者经常混淆这两个概念,两者的相同点可以归纳为三点:
下表列出了两者之间的区别,如表6.1所示。
|
区别点 |
接口 |
抽象类 |
|
含义 |
接口通常用于描述一个类的外围能力,而不是核心特征。类与接口之间的是-able或者can do的关系。 |
抽象类定义了它的后代的核心特征。派生类与抽象类之间是is-a的关系。 |
|
方法 |
接口只提供方法声明。 |
抽象类可以提供完整方法、缺省构造方法以及用于覆盖的方法声明。 |
|
变量 |
只包含public static final常量,常量必须在声明时初始化。 |
可以包含实例变量和静态变量。 |
|
多重继承 |
一个类可以继承多个接口。 |
一个类只能继承一个抽象类。 |
|
实现类 |
类可以实现多个接口。 |
类只从抽象类派生,必须重写。 |
|
适用性 |
所有的实现只是共享方法签名。 |
所有实现大同小异,并且共享状态和行为。 |
|
简洁性 |
接口中的常量都被默认为public static final,可以省略。接口中的方法被默认为public abstract。 |
可以在抽象类中放置共享代码。必须用abstract显式声明方法为抽象方法。 |
|
添加功能 |
如果为接口添加一个新的方法,则必须查找所有实现该接口的类,并为它们逐一提供该方法的实现。 |
如果为抽象类提供一个方法,可以选择提供一个缺省的实现,那么所有已存在的代码不需要修改就可以继续工作。 |
总体来说,抽象类和接口都用于为对象定义共同的行为,两者在很大程度上是可以互相替换的,但由于抽象类只允许单继承,所以当两者都可以使用时,优先考虑接口,只有当需要定义子类的行为,并为子类提供共性功能时才考虑选用抽象类。
多态是面向对象的另一大特征,封装和继承是为实现多态做准备的。简单来说,多态是具有表现多种形态的能力的特征,它可以提高程序的抽象程度和简洁性,最大程度降低了类和程序模块间的耦合性。
多态是指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在Java程序中,多态是指把类中具有相似功能的不同方法使用同一个方法名实现,从而可以使用相同的方式来调用这些具有不同功能的同名方法。
Java中的引用变量有两种类型,即声明类型和实际类型。变量声明时被指定的类型称为声明类型,而被变量引用的对象类型称为实际类型。方法可以在沿着继承链的多个类中实现,当调用实例方法时,由Java虚拟机动态地决定所调用的方法,称为动态绑定。
动态绑定机制原理是:当调用实例方法时,Java虚拟机从该变量的实际类型开始,沿着继承链向上查找该方法的实现,直到找到为止,并调用首次找到的实现。
对象的类型转换是指可以将一个对象的类型转换成继承结构中的另一种类型。类型转换分为两种,具体如下:
需要特别注意的是,向下转型时,被转换变量的实际类型,必须是转换类或其子类。
Java中提供了一个Object类,是所有类的父类,如果一个类没有显式地指定继承类,则该类的父类默认为Object。
调用一个对象的toString()方法会默认返回一个描述该对象的字符串,它由该对象所属类名、@和对象十六进制形式的内存地址组成。
通常,重写toString()方法返回对象具体的信息。
equals()方法是用于测试两个对象是否相等。
如果要检测两个不同对象的内容是否相同,就必须重写equals()方法。例如String类中的equals()方法继承自Object类并重写,使之能够检验两个字符串的内容是否相等。
工厂模式主要用来实例化有共同接口的类,它可以动态决定应该实例化哪一个类,不必事先知道每次要实例化哪一个类。工厂模式主要有三种形态:简单工厂模式、工厂方法模式和抽象工厂模式。接下来分别对这三种形态进行讲解。
简单工厂模式又称静态工厂方法,它的核心是类中包含一个静态方法,该方法用于根据参数来决定返回实现同一接口不同类的实例。
工厂类SimpleFactory有很多局限。首先,维护和新增产品时,都必须修改SimpleFactory源代码。其次,如果产品之间存在复杂的层次关系,则工厂类必须拥有复杂的逻辑判断。最后,整个系统都依赖SimpleFactory类,一旦SimpleFactory类出现问题,整个系统就将瘫痪不能运行。
工厂方法模式为工厂类定义了接口,用多态来削弱了工厂类的职责。
工厂方法模式也有局限之处,当面对有复杂的树形结构的产品时,就必须为每个产品创建一个对应的工厂类,当达到一定数量级就会出现类爆炸。
抽象工厂用于创建一系列互相关联或互相依赖的对象。
代理模式是指给某一个对象提供一个代理,并由代理对象控制对原有对象的引用。如生活中,求职者找工作(真实操作),可以让猎头帮忙去找(代理操作),猎头把最终结果反馈给求职者。无论是真实操作还是代理操作,目的都是一样的,求职者只关心最终结果,而不关心过程。
当声明的类很多时,类名就有可能冲突,这就需要一种机制来管理类名,因此,Java中引入了包机制,本节将详细介绍包的用法。
包(package)是Java提供的一种区别类的名字空间的机制,是类的组织方式,是一组相关类和接口的集合,它提供了访问权限和命名的管理机制。
使用时需要注意以下四点:
在实际开发中,项目都是分模块开发,对应模块包中的类,完成相应模块的功能。但有时模块之间的类要相互调用。例如,通常开发中都是将业务逻辑层的接口和实现放在不同包中。
为了简化编程,Java提供了import关键字,用于导入指定包层次下某个类或全部类,import语句应放在package语句之后,类定义之前。
Java的核心类都放在java包及其子包下,Java扩展的类都放在javax包及其子包下,接下来了解一下常用的开发包,如表6.3所示。
|
包名 |
功能描述 |
|
java.lang |
核心包,如String、Math、System类等,无需使用import手动导入,系统自动导入 |
|
java.util |
工具包,包含工具类、集合类等,如Arrays、List和Set等 |
|
java.net |
包含网络编程的类和接口 |
|
java.io |
包含输入、输出编程相关的类和接口 |
|
java.text |
包含格式化相关的类 |
|
java.sql |
数据库操作包,提供了各种数据库操作的类和接口 |
|
java.awt |
包含抽象窗口工具集(abstract window toolkits)相关类和接口,主要用于构建图形用户界面(GUI) |
|
java.swing |
包含图形用户界面相关类和接口 |
在实际开发中,通常会将一些类提供给别人使用,直接提供字节码文件会比较麻烦,所以一般会将这些类文件打包成jar文件,以供别人使用。jar文件的全称是Java Archive File,意思就是Java归档文件,也称为jar包。将一个jar包添加到classpath环境变量中,Java虚拟机会自动解压jar包,根据包名所对应的目录结构去查找所需的类。
通常使用jar命令来打包,可以把一个或多个路径压缩成一个jar文件。jar命令是在JDK安装目录下的bin目录中,直接在命令行中输入jar命令,即可查看jar命令的提示信息。
jar命令主要参数如下:
有了包的概念之后,接下来将系统介绍Java中访问权限的概念。它可以对类、属性以及方法进行声明和控制,以便隐藏类的一些实现细节,防止对封装数据未经许可的访问和不合理的操作。
Java中的4种访问权限级别由小到大依次如下:
接下来总结4种访问控制权限,如表5.4所示。
|
访问范围 |
private |
default |
protected |
public |
|
同一类中成员 |
√ |
√ |
√ |
√ |
|
同一包中其他类 |
|
√ |
√ |
√ |
|
不同包中子类 |
|
|
√ |
√ |
|
不同包的非子类 |
|
|
|
√ |
2.1 示例1 打印所有的水仙花数
编写程序打印出所有的水仙花数。所谓"水仙花数"是指一个三位数,其各位数字立方和等于该本身。例如:153是一个水仙花数,因为153=1^3+5^3+3^3。 输出的数之间用“,”(英文半角的逗号)
源代码
public class Main {
public static void main(String[] args) {
int a,b,c,d;
for(int i=100; i<1000; i++) {
a=i/100;
b=i%100;
c=b/10;
d=b%10;
if(i==a*a*a+c*c*c+d*d*d) {
if(i<400){
System.out.print(i+",");
}
if(i>400){
System.out.print(i);
}
}
}
}
}
测试用例
153,370,371,407
分析说明:本题要求找出符合要求的数,可以用for循环先把每一位数分离出来,如用原来的数除以100可以得到千位数,用原来的数%10可取到个位数,后将得到的每一位数按水仙花的定义进行三次方的相乘后相加,再用if结构进行判断选择,后输出结果。
首先给出所输入字符的个数N,然后给出N个字符,统计其中英文字母、空格、数字字符和其他字符的个数。
输入格式:
第一行为字符的个数N;
第二行为N个字符。
输出格式(在四行内输出):
letters=英文字母个数
blanks=空格个数
digits=数字字符个数
输入样例:
10
AaZ & 15Az
输出样例:
letters=5
blanks=2
digits=2
others=1
源代码:
import java.util.Scanner;
public class Main{
public static void main(String[]args)
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
sc.nextLine();
String str = sc.nextLine();
int letters = 0, blanks = 0, digits = 0, others = 0;
for(int i = 0; i < N; i++){
int cha = str.charAt(i);
if((cha >= 65 && cha <= 90) || (cha >= 97 && cha <= 122)){
letters++;
}else if(cha == 32){
blanks++;
}else if(cha >= 48 && cha <= 57){
digits++;
}else{
others++;
}
}
System.out.printf("letters=%d\nblanks=%d\ndigits=%d\nothers=%d",letters,blanks,digits,others);
sc.close();
}
}
测试用例:
letters=5
blanks=2
digits=2
others=1
在线测评系统使用感受
该系统练习案例经典,提交方式简便,但有时该上题目难度过大,不仅学习质量低,并且浪费时间。
改进学习方法、措施落实情况
3.1 除课堂外,遇到不会的问题时会到哪个平台搜索
CSDN和百度
3.2 根据记录2个月的每天代码时长,利用excel绘制统计表
没记录过,平均每天1.5小时看视频学习和写代码。
3.3 感觉个人的哪些方法还存在不足?哪些方面需要改进?等
训练逻辑思维的深度不够,思考题目要很久。
敲多点代码巩固知识,刷题量不够。
4. 你知道csdn么,结合使用情况表述他的优点与不足
4.1 csdn给你的直观感受是什么?
挺好的,能学到很多。
4.2 csdn你感觉最不舒服的地方是什么?
有些题目难度太难,浪费时间
4.3 你还利用了哪些平台学习编程知识,他们是哪些网站或资源,优点是什么?
B站和中国大学mooc,主要拿来看视频学习。B站的优点是能有一些小的知识点的讲解视频;慕课的优点是帮助理解课程知识。
5.你认为影响你学习编程的主要阻力是什么?如何克服!
知识面太广,多而杂,短时间内难以掌握,要花很长时间来吸收。