尚硅谷Java基础编程

title: Java基础(第一遍)

01 Java语言概述

1.1软件开发介绍

软件

一系列按照特定顺序组织的计算机数据指令的集合

  • 系统软件-Windows Linux Mac Android
  • 应用软件

流程图

TRUE
FALSE
递归函数
执行语句
条件
执行语句
退出

人机交互方式

图形化界面(Graphical User Interface GUI)

命令行方式(Command Line Interface CLI

命令行指令

切换盘符 d:

列出子目录 dir

退出当前目录 cd..

打开文档 cd

创建目录(文件夹)md

一次性退出到根目录 cd\

创建文件 echo name : tom >1.doc name : tom是需要写入的东西,可以不写\

删除文件目录rd(如果里面有内容删除不了,需要进入然后删除文件)

删除文件 del del *.txt(删除同类文件),如果直接del删除文件内的内容

退出 exit

常用快捷键

  • ← →:移动光标
  • ↑ ↓:调阅历史操作命令
  • Delete和Backspace:删除字符

1.2计算机语言介绍

什么是计算机语言

人与计算机交流的方式

语言 = 语法 + 逻辑

C,C++,Java,PHP,Kotlin,Python,Scala .et al

登录界面
HTTP

语言的分代

第一代 机器语言

第二代 汇编语言 使用助记符表示一条机器指令

第三代 高级语言

  1. 面向过程 C
  2. C ++ Cpp
  3. 面向对象 Java
高级语言
汇编语言

Android/why is Java?

市场需求

https://www.tiobe.com/tiobe-index/

C 运行效率高

  • 操作系统
  • 嵌入式设备(汽车,洗衣机)
  • 动画制图

Python 开发效率快,运行速度更低

  • 爬虫
  • 数据分析
  • AI
  • 后台
  • 自动化运维

PHP

  • 后台

C# 不开源

Java 社区最活跃

JavaScript 前端

SQL

Swift 与 OC Apple

Go Google (头条替换成Go)

1.3 Java语言概述

1995 SUN(Stanford University Network)

简史

1991 Oak(橡树)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M8pjwgsU-1596345581891)(images/image-20200721114138877.png)]

爪哇岛 生产咖啡

2004 JDK 1.5 突破版本 更名JDK 5.0

2009 74亿美元 Oracle收购

2014 JDK8.0 使用量最大

LTS 8 11 长期维护版本

每隔三年发布一个LTS

Java技术体系平台

Java SE (Java Standard Edition)标准版
支持面向桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,此版本以前称为J2SE
**Java EE(Java Enterprise Edition)企业版 **
是为开发企业环境下的应用程序提供的一套解决方案。该技术体系中包含的技术如:Servlet 、Jsp等,主要针对于Web应用程序开发。版本以前称为J2EE
Java ME(Java Micro Edition)小型版
支持Java程序运行在移动终端(手机、PDA)上的平台,对Java API有所精简,并加入了针对移动终端的支持,此版本以前称为J2ME
Java Card
支持一些Java小程序(Applets)运行在小内存设备(如智能卡)上的平台

Java语言特点

面向对象

健壮性

  • 去除了指针
  • 增加了内存管理

跨平台(write once run anywhere)

  • JVM Java虚拟机 实现Java语言跨平台
  • 不同系统的JVM不一样(Win、Linux、Mac)

1.4 运行机制及其运行过程

JVM是一个虚拟的计算机

Java舍弃了C的指针

增加了垃圾回收机制//自动的内存管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VnglIqCJ-1596345581893)(images/image-20200721143247317.png)]

1.5 Java语言的环境的搭建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmCxSigG-1596345581894)(images/image-20200721173749991.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0Cm1K7O-1596345581897)(images/image-20200721180531394.png)]

配置环境变量

需在任何文件路径下能够执行javac与java文件

path:windows在执行命令时要搜寻的路径

  1. 我的电脑–属性–高级系统设置–环境变量
  2. 编辑 path 环境变量,在变量值开始处加上java工具所在目录,后面用 “ ; ”和其他值分隔开即可。
  3. 打开DOS命令行,任意目录下敲入javac。如果出现javac 的参数信息,配置成功。

设置JAVA_HOME

新建环境变量JAVA_HOME

JAVA_HOME = C:\Program Files\Java\jdk1.8.0_131

新增Path环境变量,将

D:\developer_tools\Java\jdk1.8.0_131\bin

替换为

%JAVA_HOME%\bin;

测试

java -version

为什么要使用JAVA_HOME?

为了以后默认寻找JAVA_HOME的方便

注意:要把JAVA_HOME放在前面

1.6 开发体验-Hello World

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hYGsbqCT-1596345581898)(images/image-20200721142800174.png)]

ln为line的意思,属于单行打印

想当于打印与换行符同时进行

class HelloChina{
    public static void main(String[] args){
        System.out.println("Hello world!");
    }
    //ln是相当于print+line,属于单行打印的意思
}
class HelloChina{
    public static void main(String[] args){
        System.out.print("Hello World!");
        //单行注释,此行没有换行符
        System.out.println();
        //相当于换行符
        System.out.println("Hello WOrld!");
    }
}

写完之后注意保存

1.7 Java注释信息

文档注释的注意事项

  • 文档注释需要用于放置于类的前面用于标记声明类,放置于类后面@不展现
  • 一个java源文件声明多个类编译之后会生成多个字节码文件(对应原文件中不同的类)
  • 要想使用java.exe命令解释运行成功,必须保证对应的类中声明有main()方法。
    main()的格式是固定的!
  • main()作为程序的入口!
  • 如果源文件中的一个类想用public修饰,则要求此类的类名必须与源文件的文件名相同。
/*
一、测试Java中的三种注释

1. 单行注释 //
2. 多行注释

3. 文档注释(java特有)

二、单行和多行注释的作用:
① 对编写的代码进行解释说明
② 进行代码的调试

三、说明
1. 单行注释和多行注释,被注释掉的信息,是不参与编译的。
2. 多行注释是不能嵌套使用的。

四、文档注释

特点:
注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。
*/

    
/**
文档注释:
放置于类的前面,用于声明类的注释
这是我的第一个Java程序!
@author shkstart
@version 1.0
*/

public class CommentTest{
	/**
	如下的方法是main()方法,作为程序的入口
	*/
    
	/*
	main()的格式是固定的!
	*/
	public static void main(String[] args) {
		//单行注释
		//System.out.println("Hello World!")
	}
}

对编写的代码进行解释说明

注释相当于药的说明书

多行注释不能嵌套使用

文档注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VoH0Xa8K-1596345581901)(images/image-20200721154516861.png)]

mydoc是自己起的名字,生成文件目录

打开index首页

1.9 Java API文档

API (Application Programming Interface,应用程序编程接口)是 Java 提供的基本编程接口。

Java语言提供了大量的基础类,因此 Oracle 也为这些基础类提供了相应的API文档,用于告诉开发者如何使用这些类,以及这些类里包含的方法。类似于学习汉字使用的《新华字典》

注意搜索查看

相当于辞典

1.10 良好的编程风格

使用文档注释来注释整个类或整个方法

使用注释方法注释某一个步骤

使用TAB操作进行缩进

运算符两端加空格

块的风格可以做选择

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-foQMwXKn-1596345581903)(images/image-20200721160253466.png)]

总结

1.编写-编译-运行三个步骤:
	① 编写:将编写的java程序保存在.java结尾的源文件中。比如:Hello.java
	② 编译:使用javac.exe指令对编写的java源文件进行编译。比如:javac Hello.java
        编译之后,生成.class结尾的字节码文件。
	③ 运行:使用java.exe指令对生成的字节码文件,进行解释运行。比如:java HelloShangHai
2. 在一个java源文件中,是可以声明多个类的。那么编译之后,就会生成对应的类名的多个字节码文件。
3. 要想使用java.exe命令解释运行成功,必须保证对应的类中声明有main()方法。
   main()的格式是固定的!
4. main()作为程序的入口!
5. 如果源文件中的一个类想用public修饰,则要求此类的类名必须与源文件的文件名相同。
   > 结论:一个源文件中,最多只能有一个类声明为public6. 输出语句:
   类型一:System.out.println()  在执行完输出语句之后,会换行
   类型二:System.out.print()   在执行完输出语句之后,不会换行
7. 所有的执行语句,必须以";"结尾
*/
class HelloShangHai {
	public static void main(String[] args) {//args: arguments,参数
		System.out.println("Hello World!");
		System.out.println("Hello World!");//"Hello World!" : 字符串
		System.out.println("Hello World!");
	}
}

class HelloBeiJing{
}

class HelloShenZhen{
	public static void main(String[] args) {
		System.out.println("Hello World!");
	}
}

class HelloGuangZhou{
}

public class Hello{//public修饰与否,影响的是Hello类被调用时的权限的大小

}

02 Java基本语法

2.1 关键字和保留字

关键字(Keyword)

  • 定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)
  • 特点:关键字中所有字母都为小写

保留字(reserved word)

  • 现有Java版本尚未使用,但以后版本可能会作为关键字使用。自己命名标识符时要避免使用这些保留字
  • goto 、const
关键字 名称 介绍
byte 单字节类型 1个字节(8位)[-128,127]
short 短整型 2个字节(16位)[-215,215-1]
int 整型 4个字节(32位)[-231,231-1]
long 长整型 8个字节(64位)[-263,263-1]
char 单字符类型 2个字节(16位)
float 单精度浮点型 4个字节 科学计数法保留小数点6-7位+F或者f
double 双精度浮点型 8个字节 科学计数法表示小数点15-16位
boolean 布尔类型 true and false

2.2 标识符

Java 对各种变量方法等要素命名时使用的字符序列称为标识符

技巧:凡是自己可以起名字的地方都叫标识符

2.2.1 定义合法标识符规则:

  • 由26个英文字母大小写,0-9,_ 或 $ 组成

  • 数字不可以开头

  • 不可以使用关键字和保留字,但能包含关键字和保留字

class public1//public不行
  • Java中严格区分大小写,长度无限制,在windows中不区分大小写,会发生覆盖
  • 标识符不能包含空格

2.2.2 命名的规范

包名:多单词组成时所有字母都小写:xxxyyyzzz

类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz 大驼峰

变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz 小驼峰

常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ

如果用户不遵守规范,编译与运行都不受影响

2.3 变量

2.3.1 变量的概念

  • 内存中的一个存储区域
  • 该区域的数据可以在同一类型范围内不断变化
  • 变量是程序中最基本的存储单元。包含变量类型、变量名和存储的值

2.3.2变量的作用

  • 用于在内存中保存数据
/*
测试变量的定义
变量的声明与赋值
格式: 数据类型 变量名 = 变量值;
*/
class VaribleTest{
    public static void main(String[] args){
        int number;//变量的声明
        number = 1;//变量的赋值
        //变量的声明与赋值
        int count = 2;
        System.out.println(number + 1);
    }
}

2.3.3 变量注意点

  1. java是强类型的语言,声明的每个变量,一定要指明其变量类型
  2. 变量一定需要在赋值之后才可以使用(java没有初始化)
  3. 变量需要先声明在赋值
  4. 变量都有其作用域,超出作用域范围后,就失效 { }
  5. 在同一个作用域范围内,不能同时存在相同的变量名
/**文档注释示例

*/

2.3.4基本数据类型

<1> 数据类型的分类

按数据类型分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FAlKe5Pf-1596345581905)(images/image-20200722103300390.png)]

整型:byte\short\int\long

浮点型:float\double

字符型:char

布尔型:boolean

<2> Java整型

  • Java各整数类型有固定的表数范围和字段长度,不受具体OS的影响,以保证java程序的可移植性。
  • 超过范围编译不通过
  • java的整型常量默认为 int 型,声明long型常量须后加‘l’或‘L’,一般默认加L
  • java程序中变量通常声明为int型除非不足以表示较大的数,才使用long,一般使用int
关键字 名称 介绍
byte 单字节类型 1个字节(8位)[-128,127]
short 短整型 2个字节(16位)[-215,215-1]
int 整型 4个字节(32位)[-231,231-1]
long 长整型 8个字节(64位)[-263,263-1]
char 单字符类型 2个字节(16位)
float 单精度浮点型 4个字节 科学计数法保留小数点6-7位+F或者f
double 双精度浮点型 8个字节 科学计数法表示小数点15-16位
boolean 布尔类型 true and false

<3> Java浮点类型

与整数类型类似,Java 浮点类型也有固定的表数范围和字段长度,不受具体操作系统的影响。

浮点型常量有两种表示形式:

  • 十进制数形式:如:5.12 512.0f .512 (必须有小数点)
  • 科学计数法形式:如:5.12e2 512E2 100E-2

float:单精度,尾数可以精确到7位有效数字。很多情况下,精度很难满足需求。

定义float类型的变量在赋值时,需要’F’或者’f’,否则编译错误

float存储范围比long还要大,但是精度降低

double:双精度,精度是float的两倍。通常采用此类型

Java 的浮点型常量默认为double型,声明float型常量,须后加‘f’或‘F’

类 型 占用存储空间 表数范围
单精度float 4字节 -3.403E38 ~ 3.403E38
双精度double 8字节 -1.798E308 ~ 1.798E308

<4> 字符类型char

char 型数据用来表示通常意义上“字符” (2字节)

Java中的所有字符都使用Unicode编码,故一个字符可以存储一个字母,一个汉字,或其他书面语的一个字符

字符型变量的三种表现形式:

  • 字符常量是用单引号==‘ ’==括起来的单个字符。
char c1 = 'a';
char c2 = '1';
char c3 = 'zhong';
char c4 = 'd';
char c5 = 'ab';//编译不通过
char c6 = '';//编译不通过
  • 转义字符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W0bMfpEw-1596345581907)(images/image-20200722111203167.png)]

char c7 = '\n';//换行符
char c8 = '\t';//制表符,缩进
  • 直接使用 Unicode 值来表示字符型常量:\uXXXX。其中,XXXX代表一个十六进制整数。如:

    \u000a = \n;
    //char类型是可以进行运算的。因为它都对应有Unicode码。

u是Unicode 通过映射表进行对照

<5> Unicode 编码

Unicode:一种编码,将世界上所有的符号都纳入其中。

每一个符号都给予一个独一无二的编码,使用 Unicode 没有乱码的问题。

Unicode 的缺点

  • Unicode 只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储:无法区别 Unicode 和 ASCII:计算机无法区分三个字节表示一个符号还是分别表示三个符号。
  • 每个字符都用三个或者四个字节存储,浪费了存储空间。

Unicode向下兼容了ASCII码

<6> UTF-8

UTF-8 是在互联网上使用最广的一种 Unicode 的实现方式。

UTF-8 是一种变长的编码方式。它可以使用 1-6 个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则

  • 对于单字节的UTF-8编码,该字节的最高位为0,其余7位用来对字符进行编码(等同于ASCII码)。
  • 对于多字节的UTF-8编码,如果编码包含 n 个字节,那么第一个字节的前 n 位为1,第一个字节的第 n+1 位为0,该字节的剩余各位用来对字符进行编码。在第一个字节之后的所有的字节,都是最高两位为"10",其余6位用来对字符进行编码。

<7> ASCII码

在计算机内部,所有数据都使用二进制表示

一共规定了128个字符

//使用ASCII码对应数值
char c9 = 97;//a
char c10 = 65;//A

<8> 布尔类型:boolean

只有两个值

//常常在循环结构,条件判断结构中使用
boolean bo1 = true;
boolean bo2 = false;
if(bo1){
    System.out.println("true");
}
else{
    System.out.println("false");
}

2.4 运算规则

public class StringTest{
    public static void main(String[] args){
        int no = 10;
        String str = "abcdef";
        String str1 = str + "xyz" + no;//abcdefxyz10
        str1 = str1 + "123";//abcdefxyz10123
        char c = '国';
        
        double pi = 3.1416;
        str1 = str1 + pi;//abcdefxyz101233.1416
        boolean b = false;
        str1 = str1 + b;
        str1 = str1 + c;
        
        System.out.println("str1 = " + str1); 
    }
}

2.4.1 数据自动类型转换默认int double

  1. 当存储范围小的数据(变量/表达式/常量),赋值给存储范围大的变量时,自动升级为该存储范围大的类型

    double d = 12; 
    //容量大小指的不是数据类型占用空间的大小,指的的存储量的大小 long 与 float
    char
    int
    byte
    short
    long
    float
    double
  2. 当byte与byte,short与short,char与char,byte,short,char之间一起运算了,都会自动升级为int

    byte b1 = 1; 
    byte b2 = 2; 
    int sum = b1 + b2;//sum为int
  3. 当多种基本数据类型的数据一起混合运算,会自动升级为它们中大的类型

    char c = 'a';//97 
    int b = 12; 
    double d = 2.8; 
    double sum = c + b + d;
  4. 当基本数据类型的数据 与 String类型进行“+”拼接时,结果自动转为String类型。

    <1>String: 字符串,使用一对“”表示

    <2>String s1 = " ";内部可以声明0个,1个或者多个字符

    <3>String只能和8种基本数据类型的变量做连接运算

    <4>运算的结果只能是String类型

    String str = 12 + ""; 
    int n1 = 10;
    String s2 = "abc";
    String s3 = n1+s2;
    boolean a = true;
    String s4 = s2 + b1;//结果也是拼接上
    System.out.println(s4);//abctrue
    
    System.out.println(s2+n1+b1);//字符串的拼接
    System.out.rintln(n1+b1+s2);//从左到右计算,而int无法与boolean做运算,发生编译失败
    System.out.println(n1 + (b1 + s2));
  5. boolean类型不和其他基本数据类型发生转换

2.4.2 强制类型转换

当存储范围大的数据(变量、表达式、常量)赋值给存储范围小的变量时,都是需要强制类型转换

强制类型转换,需要使用强转符==()==

注意:可能会溢出,或者损失精度

  • 截断
  • 越界
//例如: 
double d = 1.2; 
int num = (int)d;//强制类型转换

float f1 = 12.9F;//第一种精度损失
int num1 = (int)f1;
System.out.println(num1);//截断输出,输出结果是12

int num2 = 128;//第二种精度损失
byte l2 = (byte)num2;
System.out.println(l2);//输出结果-128
double
float

当某个数据(变量、表达式、常量)想要让它按照某个大的类型进行计算时,也 可以使用强制类型转换

//例如: 
int a = 1; 
int b = 2; 
double shang = (double)a/b; 

boolean和String都是无法通过强制类型转换为基本数据类型的值。

练习

练习1

System.out.println('*'+'\t'+'*');//93
System.out.println('*'+"\t"+'*');//正常,制表符
System.out.println('*'+'\t'+"*");//51*
System.out.println("*"+'\t'+'*');//正常

练习2

int num = 10;
char c = 'a';
String s = "hello";
System.out.println(num + c + s);//107hello
System.out.println(s + c + num);//helloa10
System.out.println(num + ( c + s));//10ahello

练习3

String str1 = 4;					//判断对错:对
String str2 = 3.5f + “”;  			//判断str2对错:对
System.out.println(str2);		    //输出:3.5
System.out.println(3 + 4 + "Hello!");   //输出:7hello!
System.out.println("Hello!"+ 3 + 4);   //输出:hello!34
System.out.println('a' + 1 +"Hello!"); //输出:98hello!
System.out.println("Hello" + 'a' + 1);  //输出:helloa1

2.4.3 关于常量

int num1 = 10;
num1 = 20;
//对于整型常量而言,默认是int类型
int num2 = num1 + 30;//结果是int类型
//byte num2 = num1 + 30;运行不过
//对于浮点型常量而言,默认是double类型
double b1 = b1 + 12.3;

2.4.4 进制

<1> 进制的表示

  • 二进制(binary):以0b或0B开头

  • 十进制(decimal):

  • 八进制(octal):以数字0开头表示。

  • 十六进制(hex):以0x或0X开头表示。此处的A-F不区分大小写。

    如:0x21AF +1= 0X21B0

<2> 原码补码反码

过程 原码 反码(除符号位取反) 补码(+1)
1 0000 0001 0000 0001 0000 0001
-1 1000 0001 1111 1110 1111 1111
0000 0000

<3> 十进制转二进制

无符号数十进制数转二进制算法

十进制数重复除以2,每次的余数记录下当做二进制数位的值,直到商为0为止

举例:十进制数57转为二进制数

除法 余数
57/2 28 1
28/2 14 0
14/2 7 0
7/2 3 1
3/2 1 1
1/2 0 1

把余数列数字反向排列就得到了二进制数111001,由于intel存储的二进制数位数总是8或者8 的倍数,因此前面的空位补0

57的二进制数是00111001

<4> 二进制转十进制

位权表示法

1 0 1 1 0 1 0 1
7 6 5 4 3 2 1 0
1*27 0*26 1*25 1*24 0*23 1*22 0*21 1*20

算法:位权表示法把n位无符号数二进制整数转换为十进制数(不考虑正负数)
d e c = ( D n − 1 ∗ 2 n − 1 ) + ( D n − 2 ∗ 2 n − 2 ) + . . . + ( D 1 ∗ 2 1 + ( D 0 ∗ 2 0 ) ) dec = (D_{n-1}*2^{n-1})+(D_{n-2}*2^{n-2})+...+(D_{1}*2^{1}+(D_{0}*2^{0})) dec=(Dn12n1)+(Dn22n2)+...+(D121+(D020))

<5> 十进制转十六进制

无符号数十进制数转十六进制数算法:

十进制数重复除以16,每次的余数记录下来作为当前十六进制数位的值

直到商为0为止

举例:十进制数422转为十六进制数

除法 余数
422/16 26 6
26/16 1 A
1/16 0 1

把余数列数字反向排列就得到了十六进制数的1A6H,由于Intel存储的二进制数位数总是8或者8的倍数,因此前面空位补0, 422的十六进制为01A6H

<6> 十六进制转十进制

1 6 A 7 9 4
0001 0110 1010 0111 1001 0100
1*165 6*164 10*163 7*162 9*161 4*160

算法:位权表示法把n位无符号数十六进制整数转换为十进制数(不考虑正负数)
d e c = ( D n − 1 ∗ 1 6 n − 1 ) + ( D n − 2 ∗ 1 6 n − 2 ) + . . . + ( D 1 ∗ 1 6 1 + ( D 0 ∗ 1 6 0 ) ) dec = (D_{n-1}*16^{n-1})+(D_{n-2}*16^{n-2})+...+(D_{1}*16^{1}+(D_{0}*16^{0})) dec=(Dn116n1)+(Dn216n2)+...+(D1161+(D0160))

<7>二进制转八进制

  • 三个一位

<8>二进制转16进制

  • 四个一位

2.5 运算符

2.5.1 算术运算符

赋值运算符

比较运算符

逻辑运算符

运算符 运算 范例 结果
+ 正号 + 3 3
- 负号 b = 4; -b -4
+ 5 + 5 10
- 6 - 4 2
***** 3 * 4 12
/ 5 / 5 1
% 取模(取余) 7 % 5 2
++ 自增(前):先运算后取值 a = 2; b = ++a; a = 3;b = 3
++ 自增(后):先取值后运算 a = 2; b = a++; a = 3;b = 2
- - 自减(前):先运算后取值 a = 2; b = --a; a = 1;b = 1
- - 自减(后):先取值后运算 a = 2; b = a–; a = 1;b = 2
+ 字符串连接 “He” + ”llo” “Hello”

除法说明

//关于除法的一些说明
int m1 = 12;
int m2 = 5;//2
int m3 = m1/m2;//10
double m4 = (double) m1/m2;//2.4

整型获得数是整型

使用强制类型转换

模数符号说明

//关于模数的符号的了解
int m1 = 12%5;//
int m1 = -12%5;//-2
int m3 = 12%-5;
int m4 = -12%-5;//-2

符号与被模数相同

a++与++a说明

  • (前)++ :先自增1,在赋值

  • (后)++:先赋值,在自增1

  • –与++相同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3uOBzUQ-1596345581908)(images/image-20200724111548518.png)]

2.5.2 赋值运算符

class SetValues{
    public static void main(String[] args){
        //赋值运算符:=
        int a = 10;
        int b = 10;
        int a1,a2;
        a1 = a2 = 10;//连续赋值
        System.out.println("a="+a);
        System.out.println("b="+b);
        System.out.println("a1="+a1);
        System.out.println("a2="+a2);
        
        int a3 = 10, a4 = 10;
        System.out.println("a3="+a3);
        System.out.println("a4="+a4);
        
        int m = 10;
        m += 5;//m = m + 5
        System.out.println("m = " + m);
        //+= -= *= %=
    }
short m;
m += 5;
m = m + 5;//不相同
m =(short)(m=5);

两者有点类似

总结:开发中如果需要变量自增2,建议使用:+=2,而不是使用+2

int i = 10;
i += 5.0;//这个相同于
//i = (int)5.0;
System.out.println("i=" + i);

i+=与普通的运算式明显不同,可以理解为+=的过程中,会以 i 的类型对+=之后的数发生强制类型转换。

练习

<1> 示例1

int m1 = 2;
int n1 = 3;
n1 *= ++m1;
System.out.println("m1="+m1);//3
System.out.println("n1="+n1);//9

<2> 示例2

int n3 = 10;
n3 += (n3++) + (++n3);//n3 = n3 + (n3++) + (++n3)
System.out.println(n3);//32

在进行++或者–运算式,(a++) 这个整体已经自增1,但是赋值的情况下是先赋值,但是在进行四则运算的时候就不一样了。

<3> 示例3

多项运算式的变换

从左往右依次计算

int k = 0,j = 0;
j += k* = j += (k = 1)/(j = 1);
上述正则表达式可以进行简写
j = j + (k = k * (j = j + (k=1)/(j=1)))
System.out.println(j);//0
int k = 0;
int j = 0;
j += ++k + (++k +j);
上述可以改写成
    j = j + (++k + (++k +j))
    j = 0 + (1 + (2+0))
System.out.println(j);//3

2.5.3 比较运算符

运算符 运算 范例 结果
== 相等于 4==3 false
!= 不等于 4!=3 true
< 小于 4<3 false
> 大于 4>3 true
<= 小于等于 4<=3 false
>= 大于等于 4>=3 true
instanceof 检查是否是类的对象 “Hello” instanceof String true

说明

运算的结果是布尔类型

区分赋值符号 == =

System.out.println(a == b);//false
System.out.println(a = b);//b

2.5.4 逻辑运算符

a b a&b 且true a&&b 且true a|b a||b !a a^b 不同为true
true true true true true true false false
true false false false true true false true
false true false false true true true true
false false false false false false true false

逻辑运算符使用

&逻辑与

&&短路与

说明

操作的是boolean类型变量

运算的结果也是boolean类型

区分&与&&

boolean b1 = false;
boolean b2 = true;
int m1 = 10;
if(b1 & (m1++>0)){
    System.out.println("执行if结构");
}else{
    System.out.println("执行else结构");
}
System.out.println("m1="+m1);

int m2 = 10;
if(b1 && (m2++>0)){
    System.out.println("执行if结构");
}else{
    System.out.println("执行else结构");
}
System.out.println("m2="+m2);

int m3 = 10;
if(b2 | (m3++>0)){
    System.out.println("执行if结构");
}else{
    System.out.println("执行else结构");
}
System.out.println("m1="+m1);

int m4 = 10;
if(b2 || (m4++>0)){
    System.out.println("执行if结构");
}else{
    System.out.println("执行else结构");
}
System.out.println("m2="+m2);

& 左边是false,依然执行右边

&&左边是false,不执行右边操作(短路)

|左边是true,依然执行右边

||左边是true,不执行右边操作(短路)

结论

开发中,建议大家使用短路情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJW0FYO7-1596345581910)(images/image-20200724111722689.png)]

2.5.5 位运算符

位运算符
运算符 运算 范例
<< 左移 3 << 2 = 12 --> 322=12
>> 右移 3 >> 1 = 1 --> 3/2=1
>>> 无符号右移 3 >>> 1 = 1 --> 3/2=1
& 与运算 6 & 3 = 2
| 或运算 6 | 3 = 7
^ 异或运算 6 ^ 3 = 5
~ 取反运算 ~6 = -7

说明:

针对于整数,不管整数还是负数:左移一位乘以2,当最高位左移到边缘时,符号位发生了变化。

针对于整数,不管是正数还是负数,在一定范围内,只要向右移动了一位。就相当于/2

-7>>1;//-4

无符号位移>>>补0,用来取最小四位,如1111 0000 >>>4 = 0000 1111

增加1.5倍的算法,使用位运算

10+15;
10+10>>1;//除以2的倍数

练习

如何手动实现整型数值60的二进制到十六进制的转换

//[answer]
String str1 = Integer.toBinaryString(60);
String str2 = Integer.toHexString(60);
int i1 = 60;
int i2 = i1&15;
//通过二进制数0000 1111,获取60二进制数的低四位
String j = (i2 > 9)?(char)(i2-10+'A'):i2 + "";

int temp = i1>>>4;//无符号进位4
//通过无符号数位移获得i1的高四位二进制数
i2 = temp & 15;
String k = (i2 > 9)?(char)(i2-10+""):i2+"";
System.out.print(k+""+j);

交换两者的值

int m = 4;
int n = 2;
//方式1
int temp = m;
	   m = n;
	   n = temp;//注意斜的是一样的
//方式2,字符串类型不通用
m = m + n;
n = m - n;
m = m - n;
//方式3,使用位运算
m = m^n;//拿出两者的不同
n = m^n;//把其中一个不同改变
m = m^n;

在使用位运算中

m^n = a;//m^n^n = m
a^n = m;//n^m^m = n
int m = 4 0000 0100
int n = 2 0000 0010
进行异或位运算 1111 1001
在与2进行异或运算 0000 0100

可以预见,在与一个数进行两次异或运算后,会变成自己的本身

2.5.6 三元运算符

说明:

  • 条件表达式是 boolean 类型
  • 如果条件表达式是true,则返回表达式1
  • 如果条件表示式是false,则返回表达式2

要求表达式1和表达式2要一致

使用三元运算符的地方都可以改写为if-else

关于三元运算符比较两者相同条件下的注意事项

int m = 20;
int n = 20;
String max = (m > n)?"m大":"n大";
System.out.println(max)//n

在相同的条件下 n大

可以嵌套

//求a1,a2,a3的最大值
int max1 = (a1 > a2)?a1:a2;
int max2 = (max1 > a3)?max1:a3;
int max1 = (((a1 > a2)?a1:a2;) > a3)?((a1 > a2)?a1:a2;):a3;

在能使用三元运算符的情况下建议使用三元运算符

因为三元运算符执行效率稍微高一点

2.5.7 运算符的优先级

()

2.6 程序控制流程

2.6.0 如何获取键入的不同类型的数据

使用Scanner来实现

操作步骤

  • 导入包
  • 实例化Scanner
  • 根据需要获取变量的类型,调用相关的方法即可
import java.util.Scanner;
class ScannerTest{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);//实例化

        System.out.println("请输入姓名");
        String name = scan.next();//获取一个字符串
        System.out.println("name=" + name);
        
        System.out.println("请输入年龄");
        int age = scan.nextInt();//获取一个Int类型
        System.out.println("name=" + age);
        
        System.out.println("请输入体重");
        Double weight = scan.nextDouble();//获取一个浮点类型
        System.out.println("wieght=" + weight);
        
        System.out.println("婚否(true/false)");
        boolean isMarried = scan.nextBoolean();//获取一个布尔类型
        System.out.println("isMarried?" + isMarried);

		System.out.println("请输入您的性别");
        String gender = scan.next();
		char chargender = gender.charAt(0);//获得索引为0的字符
        System.out.println("gender:" + chargender);
    }
}

流程控制语句是用来控制程序中各个语句执行顺序的语句,可以把语句组合成 能完成一定功能的小逻辑模块

其流程控制方式采用结构化程序设计中规定的三种基本流程结构

  • 顺序结构

  • 分支结构

    if...else;
    switch-case;
  • 循环结构

    while;
    do...while;
    for;

2.6.0 如何使用equals判断字符串相等

if(height >= 180 && wealth >= 1 && "是".equals(isHandsome));
import java.util.Scanner;
class Dome10Equals{
	public static void main(String[] args){
		Scanner input = new Scanner(System.in);
		String iftest = input.next();
		boolean a = "是".equals(iftest);//如果字符串相等,则会返回true
		System.out.println(a);
	}
}

2.6.0 如何使用==Math.random()==获得随机数

如何获取一个随机数?

  1. 通过调用Math.random(),可以获取一个[0,1)范围的内的double型的随机数

  2. 获取[10,99]范围内的随机数?
    int number = (int)(Math.random() * 90 + 10);

  3. 获取[100,999]范围内的随机数?
    int number = (int)(Math.random() * (999-100+1) + 100);

总结:获取[a,b]范围的随机数的公式
( i n t ) ( M a t h . r a n d o m ( ) ∗ ( b − a + 1 ) + a ) ; (int)(Math.random() * (b - a + 1) + a); (int)(Math.random()(ba+1)+a);

int a = Math.random();
int b = (int)(Math.random()*90 + 10);//[10,100)
//获得三位随机数
int c = (int)(Math.random()*(1000-100)+100);//[100,1000)

int b = (int)(Math.random()*91 + 10);//[10,100]
//获得三位随机数
int c = (int)(Math.random()*(1001-100)+100);//[100,1000]

2.6.1 顺序结构

()

2.6.2 分支语句

条件表达式必须是布尔表达式(关系表达式或者逻辑表达式)、布尔变量

语句块只有一条执行语句,一对{}可以省掉,但是建议保留

if-else语句结构根据需要可以嵌套使用

当if-else结构是“多选一”时,最后的else是可选的。根据需要可以省掉

只执行一块代码,

执行完毕后,跳出当前if-else语句

if-else不能80

因为80与score相比已经是布尔型,布尔型不能跟90运算,所以报错

示例

class Iftest{
    public static void main(String[] args){
        int heatBeats = 80;
        if(heartBeats<60||heartBeats>100){
            System.out.println("you need continue test");
        }
        System.out.println("体检结束");
    }  
}

else根据需要来选

例题1

/**
	岳小鹏参加Java考试,他和父亲岳不群达成承诺:
	如果:
		成绩为100分时,奖励一辆BMW;
		成绩为(80,99]时,奖励一台iphone xs max;
		当成绩为[60,80]时,奖励一个 iPad;
        其它时,什么奖励也没有。
	请从键盘输入岳小鹏的期末成绩,并加以判断
*/
import java.util.Scanner;//导包

class Demo5
{
   public static void main(String[] args)
   {
       Scanner grades = new Scanner(System.in);
       System.out.print("请输入您测试得到的分数:");//给用户提示
       int grade = grades.nextInt();
       if (grade == 100){
           System.out.println("Congratlations ! You get BMW*1");
       }else if(grade>80){
           System.out.println("Congratlations ! You can get iphone xs max*1");
       }else if(grade>60){
           System.out.println("Don't worry! You can get iPad*1");
       }else{
           System.out.println("What a pity! You can't get anything");
       }
   }
}

说明

如果多个表达式彼此之间是“互斥”关系,(即:没有交集),则那个条件在上,那个在下无所谓

如果多个条件表达式彼此之间是“包含”关系,则需要将条件表达式范围小的声明在条件表达式范围大的上面

例题2 三个数字排序并输出

/**
编写程序:由键盘输入三个整数分别存入变量num1、num2、num3,对它们进行排序(使用 if-else if-else),并且从小到大输出。
*/
import java.until.Scanner;

class Demo
{
  public static void main(String[] args)
  {
      Scanner num = new Scanner(System.in);
      System.out.print("请输入num1");
      int num1 = num.nextInt();
      System.out.print("请输入num2");
      int num2 = num.nextInt();
      System.out.print("请输入num3");
      int num2 = num.nextInt();
      
      if(num1>num2)
      {
          int temp = num1;
          num1 = num2;
          num2 = temp;
      }
      if(num2>num3)
      {
          int temp = num2;
          num2 = num3;
          num3 = temp;
      }
      if(num1>num2)
      {
          int temp = num1;
          num1 = num2;
          num2 = temp;
      }
  }
}

2.6.3 分支语句2 Switch-case结构

switch(表达式)
{
    case 常量1:
        语句1;
        break;
    case 常量N:
        语句N;
        break;
    default:
        语句;
        break;
}       

break跳出当前switch-case结构

否则不会跳出代码块,依次执行

执行过程:根据switch中表达式的值,依次匹配各个case中的常量

当与某个常量匹配上时,就进入case中

调用case语句,执行完之后,依然会考虑继续执行器后的case中的结构,直接预见break

示例

public class Switchtest
{
    public static void main(String args[])
    {
        int i = 1;
        switch(i)
        {
            case 0:
                System.out.println("zreo");
                break;
            case 1:
                System.out.println("one");
            default:
                System.out.println("default");
                break;//可写可不写
        }
    }
}

局限性:

switch中的表达式的值可以是如下类型。类型存在限制,

比如boolean类型double类型不能使用

byte;
short;
char;
int;
枚举类(jak5.0新增);
String(jdk7.0新增);

表示范围不方便,但是可以通过除法进行判断,如示例1所示

case语句还可以进行合并,如示例1所示

//示例1
//对学生成绩大于60分的,输出“合格”。低于60分的,输出“不合格”
switch(score/10){
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        System.out.println("不及格");
        break;
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
        System.out.println("及格");
        break;
}
//更加注意switch结构灵活运用
switch(score/10){
    case 1:
        System.out.println("及格");
    case 0:
        System.out.println("不及格")
}

匹配的case通常不能太多

关于default默认值(相当于if-else里面的else)

可选的,位置也是灵活的

但是即使在中间插入default也是最后判断default,一般不这么书写

建议在什么情况下使用switch

switch-case可以完全转换为if-else,if-else不一定能够改写成switch-case。比如boolean类型Switch-case结构不能使用

如果判断的具体数值不多。而且符合byte、short、char、int、String、枚举等几种类型。

虽然两个语句都可以使用,建议使用switch语句。因为效率稍高。

其他情况:对区间判断,对结果为 boolean 类型判断,使用if,if的适用范围更广,也就是说,使用switch-case的,都可以改写成if-else。反之不成立

结论:如果多个语句的相同可以自动往下走,考虑合并

例题:日期与天数//Switch-case的不用break的条件

编写程序:从键盘上输入2020年的“month”和“day”,要求通过程序输出输入的日期为2020年的第几天。

import java.util.Scanner;

class Demo11Month 
{
	public static void main(String[] args) 
	{
		Scanner scan = new Scanner(System.in);
		System.out.println("请您输入月份");
		int month = scan.nextInt();//输入几月
		System.out.println("请您输入日子");
		int day = scan.nextInt();//输入几号

		int sumDays = 0;//记录总天数
		switch(month){
			case 12:
				sumDays += 30;
			case 11:
				sumDays += 31;
			case 10:
				sumDays += 30;
			case 9:
				sumDays += 31;
			case 8:
				sumDays += 31;
			case 7:
				sumDays += 30;
			case 6:
				sumDays += 31;
			case 5:
				sumDays += 30;
			case 4:
				sumDays += 31;
			case 3:
				sumDays += 29;
			case 2:
				sumDays += 31;
			case 1:
				sumDays += day;
		}
		System.out.println(month + "月份" + day + "日为本年的第"+sumDays+"天");
		System.out.println("Hello World!");
		}
}

例题:判断case里面嵌套if-else判断是否为闰年

从键盘分别输入年、月、日,判断这一天是当年的第几天

import java.util.Scanner;

class Demo11Month 
{
	public static void main(String[] args) 
	{
        Scanner scan = new Scanner(System.in);
        
		System.out.println("请您输入年份");
		int year = scan.nextInt();//输入年份
		System.out.println("请您输入月份");
		int month = scan.nextInt();//输入几月
		System.out.println("请您输入日子");
		int day = scan.nextInt();//输入几号

		int sumDays = 0;//记录总天数
		switch(month){
			case 12:
				sumDays += 30;
			case 11:
				sumDays += 31;
			case 10:
				sumDays += 30;
			case 9:
				sumDays += 31;
			case 8:
				sumDays += 31;
			case 7:
				sumDays += 30;
			case 6:
				sumDays += 31;
			case 5:
				sumDays += 30;
			case 4:
				sumDays += 31;
			case 3:
                if(year%4==0&&year%100!=0||year%400==0){//判断是否为闰年
                   sumDays += 29; 
                }else{
					sumDays += 28;
                }
			case 2:
				sumDays += 31;
			case 1:
				sumDays += day;
		}
		System.out.println("今天是"+year+"年"+month + "月" + day + "日,为本年的第"+sumDays+"天");
		System.out.println("Hello World!");
		}
}

2.6.4 循环结构1 for

反复执行特定程序

循环语句的四个组成成分

  • 初始化部分(init_statement)
  • 循环条件部分(test_exp)
  • 循环体部分(body_statement)
  • 迭代部分(alter_statement)

for 循环执行演示

for(int i = 1(第一步);i <= 100(第二步);i++(第四步))
{
    System.out.println(i);(第三步)
}

例题 输出十行hello world

for(int i = 1;i<=10;i++){
    System.out.println(i);
}

例题 遍历100以内的偶数

int sum;//记录总和
int count;
for(int i = 0;i<=100;i+=2){
    System.out.println(i);
    sum += i;
    count++;
}
System.out。println("总和为:"+sum);
System.out。println("偶数的个数为:"+count);

例题 遍历1-150倍数打印

编写程序从1循环到150,并在每行打印一个值,

另外在每个3的倍数行上打印出"foo"

在每个5的倍数行上打印"biz"

在每个7的倍数行上打印输出"baz"

class Demo12for{
    public static void main(String[] args){
        for(int i = 1;i<=150;i++){
            if(i%3==0){//判断3
                System.out.print("foo "+i);
            }else if(i%5==0){//判断5
                System.out.print("biz "+i);
            }else if(i%7==0){//判断7
				System.out.print("baz "+i);
			}else{
				System.out.println(i);
            }
        }
        System.out.println("Hello World!");
    }
}

例题 计算最大公约数与最小公倍数

输入两个正整数m和n,求其最大公约数和最小公倍数。

比如:12和20的最大公约数是4,最小公倍数是60。

说明: break 关键字的使用

总结:结束循环的方式都有哪些?

  1. 循环条件中不满足,返回false
  2. 使用break关键字
class  ForTest1{
    public static void main(String[] args){
        int m = 12;
        int n = 20;
        
        //获取连个数的较小值
        int min = (m>n)?n:m;
        
        for(int i = min;i>=1;i--)
            if(m%i==0&&n%i==0){//判断最大公约数
                System.out.println("最大公约数:"+i);
                break;
            }
                
        //获取两个数的较大值
        int max = (m>n)?m:n;
        for(int i = max; i <=m*n ;i++){
            if(i%m==0&&i%n==0){//判断最小公倍数
                System.out.printlnm("最小公倍数:"+i);
                break;
            }
        }
        
    }

2.6.5 循环结构2: while循环

for循环和while循环是可以相互转换的

关于初始化条件部分

while循环在执行结束后

初始化条件中涉及到的变量仍然可用

public class WhileLoop{
    public static void main(String args[]){
        int result = 0;
        int i = 1;(第一步)
        while (i <= 100){(第二步)
            result += 1;(第三步)
            i++;(第四步)
        }
        System.out.println("result = " = result);
    }
}

while循环与for循环的i的作用域不同

2.6.6 循环结构3:do-while循环

public class DoWhileLoop
{
    public static void main(String args[])
    {
        int result = 0;
        int i = 1;
        do
        {
            result += i;
            i++;
        }while(i <= 100);
        System.out.println("result = " + result);
    }
}

说明

do-while至少执行一次循环体

从事开发应用频次较低

//遍历100以内的偶数
int i = 0;
int sum =0;
int count = 0;
do{
    if(i%2==0){
        System.out.println(i);
        sum+=i;
        count++;
    }
    i++;
}while(i<=100);

2.6.7 嵌套循环

  1. 将一个循环结构A声明在另一个循环结构B的循环体中,则构成了嵌套循环

A:内层循环

B:外层循环

  1. 外层循环控制行数,内层循环控制列数

  2. 如果外层循环循环次数为m次,内层循环循环次数为n次,则可以理解为内层循环的循环体可以执行m*n次

class Demo{
public static void main(String[] args){
for(int j = 1; j <= 5; j++){
for(int i = 1; i <= 6 ;i++){
System.out.print("*");
}
System.out.println();
}
}




### 2.6.8 特殊流程控制语句==(break)==与==(continue)==

使用场景

- break只能用于switch语句和循环语句中。
- continue 只能用于循环语句中。


continue:结束当次循环

break:结束当前循环 结束离break最近的for

```java
class Demo{
 public static void main(String[] args){
     for(int i = 1; i <= 10;i++){
         if(i % 4 == 0){
             //break;//当前循环结束
             continue;//本次循环结束
             //System.out.println("今晚迪丽热巴要约我");
         }
         System.out.print(i);
     } 
 }
}

break、continue之后不能声明其他语句,程序永远不会执行其后的语句,否则会报错。

break越级结束指定标签对应的for

class Demo{
    public static void main(String[] args){
        label:for(int i = 1; i <= 10;i++){
            for(int j = 1; j <= 10; j++){
                if(i % 4 == 0){
                //break;//当前循环结束
                continue label;//本次循环结束
                //System.out.println("今晚迪丽热巴要约我");
            }
            System.out.print(i);
            }
        } 
    }
}

2.6.9 循环语句无限循环for(;while(true)

从键盘读入个数不确定的整数,并且判断读入的正数与负数的个数,输入为0时结束程序

无限循环的存在的原因是并不知道循环多少次

需要根据循环体内部的某些条件来控制循环的结束

for(;;)//while(true){
    Scanner.out.println("");
    int num = scan.nextInt();
    if(num>0)
        positiveNumber++;
    else if(num<0)
        negativeNumber++;
    else
       break;
}

打印**

/*
******
******
******
******
******
*/
class Demo14{
    public static void main (String[] args){
        for(int i = 0 ; i < 5 ; i++){
            for(int j = 0;j < 6 ; j++){
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

打印倾斜**

/*
*
**
***
****
*****
*/
class Demo15{
    public static void main (String[] args){
        for(int i = 0 ; i < 5 ; i++){
            for(int j = 0 ;j <=i ; j++){
                System.out.print("*");
            }
            System.out.println();
        }
    }

类似于数轴

打印倒着的**

/*
**** 
***
**
*
*/
class Demo{
    public static void main(String[] args){
        for(int i = 1; i <= 4; i++){
            for(int j = 1;j <= 5-i;j++){
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

打印上下两种部分**

打印**要注意i与j的数量,分析内层j与外层循环的关系

public class PrintStarTest {
    public static void main(String[] args) {
        /*
           i    j
    *****  1    5
    ****   2    4
    ***    3    3
    **     4    3
    *      5    1   所以内层循环每次都是从j=1打印到6-i次为止
         */
        for(int i = 1; i <= 5 ; i++){
            for(int j = 1; j <= 6-i ; j++){
                System.out.print("*");
            }
            System.out.println();
        }

        /*
        上半部分    i   j(-)    k(*)
        ----*      1    4       1
        ---* *     2    3       2
        --* * *    3    2       3
        _* * * *   4    1       4
        * * * * *  5    0       5

        下半部分   i     j      k
        * * * *   1     4      0
        -* * *    2     3      1
        --* *     3     2      2
        ---*      4     1      3
         */

        //上半部分的打印
        for(int i = 1; i <= 5 ; i++){
            for(int j = 1; j <= 5-i ; j++){
                System.out.print("-");
            }
            for(int k = 1; k <= i ; k++){
                System.out.print("* ");
            }
            System.out.println();
        }
        System.out.println("######################");
        //下半部分的打印
        for(int i = 1; i <= 4 ; i++){
            for(int j = 1; j < i ; j++){
                System.out.print(" ");
            }
            for(int k = 1; k <= 5-i ; k++){
                System.out.print("* ");
            }
            System.out.println();
        }
    }
}

2.6.10 嵌套循环的经典例题

九九乘法表

class Demo{
    public static void main(String[] args){
    
    for(int i = 1;i <= 9;i++){
        for(int j = 1;  j<=i ;j++){
            System.out.print(j + " * " + i + " = " +  i * j);
        }
        System.out.println();
    }
    }
}

100以内所有的质数自然数

题目:100以内的所有质数

质数(或素数):只能被1和他本身整除的自然数

比如:2, 3, 5,7,11,13,17,19,23,… 59

class Demo{
    public static void main(String[] args){
        boolean isFlag = true;
        for(int i = 2;i <= 100; i++){    
            for(int j = 2;j < i;j++){
                if(i % j == 0){
					isFlag = false;
                }
            }
            //判断isFlag是否曾经被赋值为false
            if(isFlag){
                System.out.println(i);
            }
			
			isFlag = true;//重置
        }
    }
}

遍历100 000以内的质数,判断执行效率,利用毫秒数

public class PrimeNumberTest1 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        boolean isPrime = true;
        int count = 0;
        for(int i = 2; i < 100000 ; i++){
            for(int j = 2; j < Math.sqrt(i); j++){//优化1 j < i
                if (i % j == 0) {
                    isPrime = false;
                    break;//优化2
                }
            }
            if(isPrime){
                System.out.println(i);
                count++;
            }
            isPrime = true;
        }
        long end = System.currentTimeMillis();
        System.out.println("质数个数为:"+count);
        System.out.println("花费的总时间为(毫秒):" + (end - start));
    }//17298-211
}

关于math.sqrt的理解

对于100以内的数可以说,取半就可以判断是否存在因子,但是50*2=100,

判断了2就无需在判断50,因此判断了10之后,就无需继续往后判断

03 数组

3.1 数组的概述

数组(Array),是多个相同类型数据按一定顺序排列的集合,

并使用一个名字命名,

并通过编号的方式对这些数据进行统一管理。

数组的常见概念

  • 数组名
  • 下标(或索引)
  • 元素
  • 数组的长度

3.2 一维数组的使用

3.2.1数组的声明和初始化

格式:数据类型 变量名 = 变量值

int num = 10;
String str = "Hello";

//声明
String[] foods ;
//初始化
foods = new String[]{"拌海蜇","龙须菜","西湖醋鱼"};
//声明并初始化
//静态初始化:数组变量的赋值操作与数组元素的赋值操作同时进行
String[] names = new String[]{"李金鑫""刘志引""徐德三"};
//可以简写为:String[] names = {"李金鑫","刘志引","徐德三"};

//动态初始化:数组变量的赋值操作与数组元素的赋值操作分开进行
double[] prices = new double[5];

简单整理

数组的声明;

double[] prices = new double[]{2,5,6,2}; 静态数组
double[] prices = new double[5]; 动态数组
  
int[] arr = {1,2,3};类型推断

数组一旦初始化(不管是静态还是动态初始化,长度就已经确定了)

数组一旦初始化,(不管是静态还是动态初始化,其长度就是不可变的)

错误

//t[] arr = new double[5]{1,2,3,4,5};
//t[5] arr = new int[5];

3.2.2 如何调用数组的元素

通过角标的方式进行调用

角标从0开始

prices[0] = 12.3;

prices[1] = 23.4;

prices[5]越界报错

out of bounds exception

3.2.3 如何获得数组的长度

属性:length

System.out.println(prices.length)

3.2.4 如何遍历数组元素

for(int i = 0; i < names.length ; i ++){
    System.out.println(names[i]);
}

3.2.5 数组元素的默认初始化值

double[] prices = new double[5];
price[0] = 12.3;
prices[1] = 24.4;
System.out.println(price[2]);

int[] arr = new int[]{1,2,3,4};
SYstem.out.println(arr[0]);

以动态初始化值为例

数组元素类型 元素默认初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char 0 或写为:’\u0000’(表现为空)
boolean false
引用类型 null

3.2.6 一维数组的内存解析

栈(stack)特点: 先进后出

堆(heap)

方法区

一个方法对应一个栈针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-731rZwek-1596345581913)(images/image-20200727195800509.png)]

内存内的运行方式具体如图所示,在内存中,栈主要存储数组的索引,也就是数组的第一个值

然后数组的具体存储在堆中,通过赋值对栈与堆具体的数值不断更新

通过定义数组后,原来的索引失效,java会自动垃圾回收

当main函数执行完毕后,会自行发生垃圾回收

练习1

升景坊单间短期出租4个月,550元/月(水电煤公摊,网费35元/月),空调、卫生间、厨房齐全。屋内均是IT行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。

public class ArrayTest {
      public static void main(String[] args) {
      int[] arr = new int[]{8,2,1,0,3};
      int[] index = new int[]{2,0,3,2,4,0,1,3,2,3,3};
      String tel = "";
      for(int i = 0;i < index.length;i++){
            tel += arr[index[i]];
      }
      System.out.println("联系方式:" + tel);
      }
}

练习2

从键盘读入学生成绩,找出最高分,并输出学生成绩等级。

  1. 成绩>=最高分-10 等级为’A’
  2. 成绩>=最高分-20 等级为’B’
  3. 成绩>=最高分-30 等级为’C’
  4. 其余 等级为’D’

提示:先读入学生人数,根据人数创建int数组,存放学生成绩。

import java.util.Scanner;
/**
 * @author Jinxin Li
 * @create 2020-07-27 21:02
 * 从键盘读入学生成绩,找出最高分,并输出学生成绩等级。
 * 	成绩>=最高分-10    等级为’A’
 * 	成绩>=最高分-20    等级为’B’
 * 	成绩>=最高分-30    等级为’C’
 * 	其余                        等级为’D’
 * 提示:先读入学生人数,根据人数创建int数组,存放学生成绩
 */
public class HomeWork3 {
    public static void main(String[] args) {
       Scanner scan = new Scanner(System.in);
       System.out.print("请输入学生人数");
       int studentsNum = scan.nextInt();

       //定义数组学生成绩
       int arr[] = new int[studentsNum];
       int i = 0;
       System.out.println("请您输入" + studentsNum + "个成绩");
       while(i < studentsNum){
            int studentScore = scan.nextInt();
            arr[i] = studentScore;
            i++;
        }

       //找出最高分
        int max = 0;
        for(int j = 0; j < arr.length; j++ ){
            if(arr[j] > max){
                max = arr[j];
            }
        }
        System.out.println("最高分是" + max);

        //判断输出学生成绩
        for(int j = 0;j < arr.length; j++){
            if(arr[j]>(max - 10)){
                System.out.println("student "+ j + " score is " + arr[j] + " grade is A");
            }else if(arr[j]>(max - 20)){
                System.out.println("student "+ j + " score is " + arr[j] + " grade is B");
            }else if(arr[j]>(max - 30)){
                System.out.println("student "+ j + " score is " + arr[j] + " grade is C");
            }else
                System.out.println("student "+ j + " score is " + arr[j] + " grade is D");
        }

    }
}

3.3 多维数组的使用

多维数组中主要讨论二维数组

3.3.1 二位数组的声明和初始化

静态初始化

int[][] arr = new int[][]{{1,2,3},{4,5},{6,7,8},{9,8,6,4}};

String[][] arr1 = new String[][]{{"陈伟霆","刘诗诗"},{"周笔畅"}};

动态初始化

//1
int[][] arr3 = new int[4][3];
//2
int[][] arr4 = new int[4][];
//继续定义arr4[0]第一个子数组
arr4[0] = new int[3];

/*
与一维数组的定义类似
double[] prices = new double[5];
*/

//也是正确的结构
int arr5[] = new int[5];
int arr6[][] = new int[5][7];
int[] arr7[] = new int[5][7];

关于动态初始化2

arr4[0][0] = 10;
//无指针异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EwF5n8Q-1596345581914)(images/image-20200728102930202.png)]

3.3.2 二维数组元素的调用

通过角标的使用调用二维数组的元素

System.out.println(arr[1][2]);

arr3[4][3] = 10;

3.3.3 二维数组的长度

System.out.println(arr3.length);
//4,二维数组外层数组的长度
System.out.println(arr[0].length);
//3, 二维数组内层数组的长度

3.3.4 二维数组的遍历

for(int i = 0 ; i < arr1.length ; i++){
    for(int j =0 ; j < arr1[i].length; j++)
    {
        System.out.print(arr1[i][j] +"\t");
    }
    System.out.println();
}

3.3.5 二位数组元素的默认初始化值

强类型 = 赋予什么类型,使用什么类型

对于二维数组来说,约定称谓:

外层元素,比如:arr1[0],arr1[1]

存储代表的一维数组的地址值(类型)

内层元素:比如:arr1[0][1] arr1[1][0]

存储与一维数组一样

外层地址打印输出地址+

int[][] arr1 = new int[4][4]
Ststem.out.println(arr1[0]);//外层数组打印输出地址
//引用类型默认初始化类型为null
int[][] arr3 = new int[4][];
System.out.println(arr3[0]);//null
System.out.println(arr3[0][0]);//空指针异常

arr3[0] = new int[4];
arr3[1] = new int[]{1,2,3}
arr3[2] = new int[5];
arr3[3] = new int[6];

3.3.6 二维数组的内存解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0IZZw8s0-1596345581916)(images/image-20200728182924337.png)]

练习2 求数组所有元素的和

获取arr数组中所有元素的和。

提示:使用for的嵌套循环即可。

j i j = 0 j = 1 j = 2 j = 3
i = 0 3 5 8 -
i = 1 12 9 - -
i = 2 7 0 6 4
/**
 * @author Jinxin Li
 * @create 2020-07-28 18:31
 * 求数组中元素的和
 */
public class SumArrays {
    public static void main(String[] args) {
        int[][] array = new int[][]{{3,5,8},{12,9},{7,0,6,4}};

        int sum = 0;//定义求和
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                sum += array[i][j];
            }
        }
        System.out.println("和为:" + sum);
    }
}

练习3 判断是否成立

类型相同,模式相同
声明:int[] x,y[]; 在给x,y变量赋值以后,以下选项允许通过编译的是: 
a )   x[0] = y;        no
b)    y[0] = x;        yes
c)    y[0][0] = x;     no
d)    x[0][0] = y;     no
e)    y[0][0] = x[0];  yes
f)    x = y;           no

提示:
一维数组:int[] x  或者int x[]   
二维数组:int[][] y 或者  int[] y[]  或者 int  y[][]

赋值符号左右两边类型相同

练习4 10行杨辉三角 二维数组

  1. 第一行有 1 个元素, 第 n 行有 n 个元素

  2. 每一行的第一个元素和最后一个元素都是 1

  3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。即:

//从第三行开始,对于非第一个元素,数等于左上角元素+顶上元素
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-unTL5wjQ-1596345581918)(images/image-20200728114200227.png)]

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-28 14:19
 */
public class YangHuiTriangle {
    public static void main(String[] args) {
        int[][] arr = new int[10][];

        //定义数组形状,赋值为0
        for (int i = 0; i < arr.length; i++){
            for (int j = 0; j <= i; j++) {
                arr[i] = new int[i+1];//每一个内层数组都有i+1的元素
            }
        }

        //为外层赋值
        for(int i = 0; i < arr.length; i++){
            arr[i][0] = 1;
            arr[i][i] = 1;
        }

        //为内层赋值
        for(int i = 2; i <arr.length;i++){
            for (int j = 1; j < arr[i].length-1; j++) {//最后一个数与第一个数不需要赋值
                arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
            }
        }

        //输出数列
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + "\t");
            }
            System.out.println();
        }
    }
}

练习 5 各不相同的彩票随机数

创建一个长度为6的int型数组,要求数组元素的值都在1-30之间,且是随机赋值。同时,要求元素的值各不相同。 Math.random()

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-28 8:25
 * 创建一个长度为6的int型数组,
 * 要求数组元素的值都在1-30之间,且是随机赋值。
 * 同时,要求元素的值各不相同。 Math.random()
 */
public class ChapterPractice {
    public static void main(String[] args) {
        int[] arr = new int[20];

        //赋值
        for(int i = 0;i < arr.length; i++){
                arr[i] = (int)(Math.random()*30 + 1);
                for (int j = 0; j < i; j++){
                    if(arr[i] == arr[j]){
                        i--;//利用i--表示返回思想
                        break;
                    }
                }
        }
        //输出
        for(int i = 0;i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

练习 6 回形数

打印一个5的回形数

1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

练习7 赋值与复制

使用简单数组

(1)创建一个名为ArrayTest的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。

(2)使用大括号{},把array1初始化为8个素数:2,3,5,7,11,13,17,19。

(3)显示array1的内容。

(4)赋值array2变量等于array1,修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)。打印出array1。 array2 = array1;

public class ArrayTest {
    public static void main(String[] args) {
        
        int[] arr1,arr2;

        //静态初始化8个素数
        arr1 = new int[]{2,3,5,7,11,13,17,19};
        System.out.println("显示arr1的值");
        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + "\t");
        }
        System.out.println();

        //赋值arr2
        arr2 = arr1;//单纯的传递地址,并没有new出新数列
        System.out.println("显示arr2的值");
        for (int i = 0; i < arr2.length; i++) {
            if(i%2 == 0) {
                arr2[i] = i;
            }
            System.out.print(arr2[i] + "\t");
        }
        System.out.println();

        System.out.println("显示arr1的值");

        for (int i = 0; i < arr1.length; i++) {
            System.out.print( arr1[i] + "\t");
        }
    }
}

结果:

显示arr1的值
2 3 5 7 11 13 17 19
显示arr2的值
0 3 2 7 4 13 6 19
显示arr1的值
0 3 2 7 4 13 6 19
Process finished with exit code 0

可以看出arr2改变之后,arr1也进行了改变,两者赋值给予的是地址

类似于,放置快捷方式

如果是复制才可以进行真正的赋值操作

数组的复制操作

//复制arr1到arr2
arr2 = new int[arr1.length];
for(int i = 0; i <arr2.length; i++){
    arr2[i] = arr1[i]
}

3.4 数组中涉及到的常见算法

3.4.1 数组元素的赋值(杨辉三角,回形数)

见上文

3.4.2 求数值的最大值,最小值,总和,平均数

见上文

3.4.3 数组的赋值、反转查找(线性查找,二分法查找)

反转操作

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-28 19:18
 * 反转数组
 * int[] arr1 = new int[]{3,4,5,3,6,23,6,84,4};
 */
public class ReverseArray {
    public static void main(String[] args) {
        int[] arr1 = new int[]{3,4,5,3,6,23,6,84,4};
//        打印数组
        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + "\t");
        }

        System.out.println();
//        method1
        for (int i = 0; i < arr1.length/2; i++) {//交换到一半即可,除法向上取整数,所以不用担心
            int temp = arr1[i];
            arr1[i] = arr1[arr1.length-1-i];//两端交换,注意-1为最后一位索引,然后逐步往中间靠拢
            arr1[arr1.length-1-i] = temp;
        }

        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + "\t");
        }
        System.out.println();
//        method2
        for (int i = 0,j = arr1.length; i < arr1.length/2; i++,j--) {//两边同时走
            int temp = arr1[i];
            arr1[i] = arr1[j-1];
            arr1[j-1] = temp;
        }
        for (int i = 0; i < arr1.length; i++) {
            System.out.print(arr1[i] + "\t");
        }
    }
}

查找操作-线性查找

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-28 19:33
 * 线性查找
 */
public class LineSearch {
    public static void main(String[] args) {
        int[] arr3 = new int[]{3,14,5,13,6,23,16,84,4};

//        boolean Flag = true;//定义判断没找到的标志
        int i = 0;//此处把y放在外面
        for (; i < arr3.length; i++) {
            if(arr3[i] == 100){
                System.out.println("您要找的数"+arr3[i]+"的索引是"+i);
//                Flag = false;
                break;
            }

//        if(Flag){
//            System.out.println("未找到您要搜索的数值");
//        }
        }
        if(i == arr3.length){//若没有找到
            System.out.println("未找到您要搜索的数值");
        }
    }
}

二分法需要在有序数组中进行查找

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-28 19:46
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] arr4 = new int[]{-99, -54, -2, 0, 2, 33, 43, 256, 999};
        boolean isFlag = true;
        int number = 256;
        int head = 0;//首索引位置
        int end = arr4.length - 1;//尾索引位置
        while(head <= end){
            int middle = (head + end) / 2;
            if(arr4[middle] == number){
                System.out.println("找到指定的元素,索引为:" + middle);
                isFlag = false;
                break;
            }else if(arr4[middle] > number){
                end = middle - 1;
            }else{//arr4[middle] < number
                head = middle + 1;
            }
        }

        if(isFlag){
            System.out.println("未找到指定的元素");
        }
    }
}

3.4.4 数组元素排序算法

排序

假设含有n个记录的序列为{R1,R2,…,Rn},

其相应的关键字序列为{K1,K2,…,Kn}。

将这些记录重新排序为{Ri1,Ri2,…,Rin},

使得相应的关键字值满足条Ki1<=Ki2<=…<=Kin,这样的一种操作称为排序。

通常来说,排序的目的是快速查找

排序算法的优劣

1.时间复杂度:分析关键字的比较次数和记录的移动次数

2.空间复杂度:分析排序算法中需要多少辅助内存

3.稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,

则称这种排序算法是稳定的{4,4-1},排完序列发现{4-1,4}称为不稳定的

排序方法分类

内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成。

外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。

十大内部排序方法

  • 选择排序
  • 直接选择排序、堆排序
  • 交换排序
  • 冒泡排序快速排序
  • 插入排序
  • 直接插入排序、折半插入排序、Shell排序
  • 归并排序
  • 桶式排序
  • 基数排序

快速排序


冒泡排序(会写)

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-28 16:15
 * 冒泡排序
 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = new int[]{23,34,56,234,56,34,45,89,54,69};
        for (int i = 0; i < arr.length-1; i++) {//关于length - 1 为长度
            for (int j = 0; j < arr.length-1-i; j++) {//
                if(arr[j] > arr[j+1]) {
                    int temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
        }
    }
}

3.5 Arrays工具类的使用

1 boolean equals(int[] a,int[] b) 判断两个数组是否相等。
2 String toString(int[] a) 输出数组信息。
3 void fill(int[] a,int val**)** 将指定值填充到数组之中。
4 void sort(int[] a) 对数组进行排序。
5 int binarySearch(int[] a,int key) 对排序后的数组进行二分法检索指定的值。
6 copyOf (int[],0,8) 复制
package AfterClass;

import java.util.Arrays;

/**
 * @author Jinxin Li
 * @create 2020-07-28 20:00
 * Array工具类的使用
 */
public class ArraysTools {
    public static void main(String[] args) {
        int[] arr1 = new int[]{1,2,3,4,5};
        int[] arr2 = new int[]{1,2,3,4,5};
        System.out.println(arr1 == arr2);//false,两者地址不同

        //1.equals() 判断两个数组是否相等,顺序也在其中
        System.out.println(Arrays.equals(arr1,arr2));

        //2.toString()
        System.out.println(arr1);//打印数组的地址
        System.out.println(Arrays.toString(arr1));

        //3.fill()填充
        Arrays.fill(arr1,10);//自动补充
        System.out.println(Arrays.toString(arr1));

        //4.sort()//快速排序
        int[] arr3 = new int[]{3,14,5,13,6,23,16,84,4};
        Arrays.sort(arr3);
        System.out.println(Arrays.toString((arr3)));

        //5.binarySearch()
        // 前提:数组必须有序
        int index = Arrays.binarySearch(arr3,23);
        if (index >= 0){
            System.out.println("找到了指定元素,位置为:" + index);
        }else{
            System.out.println("未找到指定元素");
        }


    }
}

3.6 数组使用中的常见异常

package com.atguigu.java1;

/**
 * 测试数组中的常见异常
 * @author shkstart
 * @create 2020-07-28 16:26
 */
public class ArrayExceptionTest {
    public static void main(String[] args) {
        //1. 数组角标越界异常:ArrayIndexOutOfBoundsException
        int[] arr = new int[10];//0-9
        System.out.println(arr[9]);
//        System.out.println(arr[10]);//越界
//        System.out.println(arr[-10]);//越界

        //2. 空指针异常:NullPointerException
        //情况1:
//        int[] arr1 = new int[10];
//        arr1 = null;
//        System.out.println(arr1[0]);

        //情况2:
//        int[][] arr2 = new int[5][];
//        System.out.println(arr2[0][0]);


        //情况3:
        String[] arr3 = new String[5];
        System.out.println(arr3[0].toString());
    }
}

04 面向对象编程(上)

4.1面向对象与面向过程

学些面向对象的三个主线(老师总结)

  • Java类及类的成员:属性 方法 构造器 代码块 内部类
  • 面向对象的三大特征: 封装 继承 多态
  • 其他关键字:this super import package static final abstract interface

面向过程与面向对象

面向过程(POP)与面向对象(OOP)

二者都是一种思想,面向对象是相对于面向过程而言的。

二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。

面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。

面向对象的三大特征

  • 封装 (Encapsulation)
  • 继承 (Inheritance)
  • 多态 (Polymorphism)

面向对象:Object Oriented Programming

面向过程:Procedure Oriented Programming

4.2 Java语言的基本元素 类和对象

类(Class)和对象(Object)是面向对象的核心概念。、

4.2.1 类与对象

类:是对一类事物的描述,是抽象的、概念上的定义

对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)

万事万物皆对象

String有两种方式

String str1 = "Hello";
String str2 = new String(orginal:"Hello")

4.2.2 设计类 其实就是设计类内部成员

属性:对应类中的成员变量

成员变量 = field = 域 = 字段

行为:对应类中的成员方法

方法 = 成员方法 = 函数 = 成员函数 = method

//设计类
class Phone{//类
    //属性
    String name;//品牌名
    double price;//价格

    //类中的方法
    public void call(){
        System.out.println("打电话");
    }

    public void sendMessage(String message){
        System.out.println("发出的信息为:" + message);
    }

}

4.3 对象的创建和使用

对类的实例化 = 创建累的对象

//创建Phone的对象

public static void main(String[] args) {
        //创建Phone的对象
        Phone p1 = new Phone();
        System.out.println("品牌名:" + p1.name + ", 价格为:" + p1.price);

        //通过"对象.方法" 或 "对象.属性"的方式调用功能,完成设计
        p1.name = "huawei p40 pro";
        p1.price = 8000.0;

        System.out.println("品牌名:" + p1.name + ", 价格为:" + p1.price);

        p1.call();
        p1.sendMessage("有内鬼,停止交易!");

        System.out.println("##########################");
    //创建第二个对象
        Phone p2 = new Phone();
        p2.name = "xiaomi 10";

        Phone p3 = p1;
        p3.price = 7000.0;
        System.out.println(p1.price);
    }

通过“对象.方法“ 或 ”对象.属性“的方式调用功能

面向对象编程思想落地的实现

步骤1:创建类,设计类的成员:属性,方法

步骤2:创建类的对象(或 类的实例化)

步骤3:调用“对象.方法” 与 “对象.属性”

4.3.1 对象的内存解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oh3Gjyc0-1596345581920)(images/image-20200729102502319.png)]

内存解析 对象名保存栈空间中

对象实体 也保存在堆空间中

对象的属性也保存在堆空间中

4.3.2 创建类的多个对象

创建类的多个对象。每个对象就拥有一套类的属性

当修改其中某一个对象的属性a,不会影响其他对象。

如果将一个对象的引用赋值给另一个对象的引用。则表示两个引用同时指向了堆空间的同一个对象实体

4.4 类中的属性的声明

4.4.1 变量的分类

  • 1)按数据类型来分:基本数据类型 (8种) vs 引用数据类型(数组、类、接口)
  • 2)按在类中声明的位置: 成员变量 vs 局部变量
  •      成员变量:直接声明在类中。
    
  •      局部变量:方法内、构造器内、代码块内、方法的形参、构造器的形参等
    

4.4.2 成员变量(类中属性)与局部变量(方法内)

成员变量与局部变量上文可见,直接上代码

public class PersonTest {//测试类

    public static void main(String[] args) {
        Person p1 = new Person();
        System.out.println(p1.name);
        System.out.println(p1.age);
        System.out.println(p1.gender);

        p1.eat("鱼香肉丝");

        p1.name = "李金鑫";
    }
}


class Person{//类
    //属性(或成员变量)
    String name;
    int age;
    boolean gender;//true:女性  false:男性
    //方法
    public void eat(String food){//food:形参。形参属于局部变量
        System.out.println("我喜欢吃:" + food);
    }

    public void sleep(){
        int minHour = 6; //属于局部变量
        int maxHour = 10;//属于局部变量
        System.out.println("每天睡眠建议不要少于" + minHour + ",但是也不要睡的过多。建议不要超过" + maxHour + "小时");
    }
}

相同点:

都是变量,定义的格式相同:数据类型 变量名 = 变量值

先声明,后使用

变量都有其作用域。超出作用域就失效

不同点:

① 关于权限修饰符的使用(了解)

成员变量声明前可以使用不同的权限修饰符进行修饰。比如:private \ 缺省 \ protected \ public

局部变量不能使用权限修饰符进行修饰。

② 关于变量赋值的说明

成员变量可以显式赋值,也可以使用默认初始化值

局部变量必须在调用之前显式赋值。因为其没有默认初始化值

对于成员变量默认初始化值的情况:

  • 整型,默认值为:0
  • 浮点型:默认值为:0.0
  • char型:默认值为:0 或 ‘\u0000’
  • boolean型:默认值为:false
  • 引用数据类型:默认值为null

③ 在类中声明的位置不同

成员变量:直接声明在类内部

局部变量:声明在方法内、构造器内、代码块内、方法的形参、构造器的形参等

④ 在内存结构中的位置不同

成员变量:声明在堆空间中

局部变量:声明在栈空间中

4.5 类中的方法的声明

4.5.1 方法声明的整体格式

权限修饰符 返回值类型 方法名(参数类型1 参数名1,参数类型2 参数名2,…)

//方法体

说明:

<1> 权限修饰符:可以使用4种不同的权限修饰来修饰方法。比如:private \ 缺省 \ protected \ public

暂时大家在声明方法时,可以默认都声明为:public

可以表明结构被调用时的权限的大小

<2> 返回值类型

  • 没有返回值,使用void表示。比如:Arrays的sort()

    Arrays.sort(arr)

  • 有具体的返回值类型,声明了返回值类型 可以是任意的基本数据类型,或者引用数据类型

    Arrays.binarySearch(int[] arr,int target);
    Arrays.equals(int[] arr,int[] arr1);
    Math.random();
    sqrt(double value)

有具体的返回值类型的方法中,一定会使用return + 变量/常量的方法,满足具体类型的数据

有返回值必有返回类型;一定会使用return

注意点:

返回值会产生自动类型提升

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BeYKeoYg-1596345581920)(images/image-20200729113917995.png)]

4.5.2 方法名

属于标识符,命名时满足标识符的规范

4.5.3 形参列表

可以再声明方法时,在()括号中存入该方法体在执行过程中必要的数据

互相之间加逗号

举例子

Arrays.binarySearch(int[] arr, int target);
Arrays.equals(int[] arr, int[] arr1);
Math.random();//这个在调用时就不要添加形式参数
sqrt(double value);

4.5.4 方法体

方法执行的结构

此外方法还可以使用一些关键字进行修饰

static

abstract

final

方法还可以抛出异常类型,异常类型见

声明方法时是否需要返回值类型,是否需要形参列表

看题目的要求

具体问题具体分析

4.5.5 return 的使用

<1> 一旦执行此关键字,就结束方法的执行

public void printNumber(){
    for(int i = 1; i <= 100; i++){
        if(i == 10){
            return;//在此处执行return之后,程序直接结束,将不会再执行下面的sout操作
        }
        System.out.println(i);
    }
}

<2> 在有返回值类型的方法中,使用return + 变量的结构,返回需要的数据类型对应的数据

public class UserTest {
    public static void main(String[] args) {
        int[] arr = new int[]{45,63,5,5,34,57};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));

        User u1 = new User();
        u1.eat("水煮鱼");

        int years = u1.studyYears();
        System.out.println(years);//12

        System.out.println("############");
        u1.printNumber();
    }
}

class User{
    //属性
    String name;
    int age = 1;

    //方法的声明
    public void eat(String food){//food:形参。形参属于局部变量
        System.out.println("我喜欢吃:" + food);
    }

    public void sleep(){
        int minHour = 6; //属于局部变量
        int maxHour = 10;//属于局部变量
        System.out.println("每天睡眠建议不要少于" + minHour + ",但是也不要睡的过多。建议不要超过" + maxHour + "小时");
        return;
    }

    public int studyYears(){
        byte years = 12;
        return years;
    }


    public void printNumber(){
        for(int i = 1;i <= 100;i++){

            if(i == 10){
                return;
            }

            System.out.println(i);

        }

        System.out.println("hello");
    }
}

方法可以调用方法

4.5.0练习3

对象数组题目

定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。

问题一:打印出3年级(state值为3)的学生信息。

问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息

提示:

  1. 生成随机数:Math.random(),返回值类型double;

  2. 四舍五入取整:Math.round(double d),返回值类型long。

public class Practice5 {
    public static void main(String[] args) {
        //1.创建student类型的数组
        Student[] stus = new Student[20];//自己定义的类,引用型,可以给自己赋值

        //2.通过循环给每个数组元素赋值
        for (int i = 0; i < stus.length; i++) {
            stus[i] = new Student();
            stus[i].number = i + 1;
            stus[i].state = (int) (Math.random() * 6 + 1);
            stus[i].score = (int) (Math.random() * 101);
            stus[i].Information();
        }

        //打印三年级学生的信息
        for (int i = 0; i < stus.length; i++) {
            if (stus[i].state == 3) {
                System.out.println("三年级的学生的成绩");
                stus[i].Information();
            }
        }

        System.out.println("学生成绩排序");

        //使用冒泡排序排序学生成绩
        for (int i = 0; i < stus.length-1; i++) {
            for (int j = 0; j < stus.length-1-i; j++) {
                if (stus[j].score > stus[j+1].score) {
                    Student temp = stus[j];
                    stus[j] = stus[j+1];
                    stus[j+1] = temp;
                }
            }
        }
        for (int i = 0; i < stus.length; i++) {
            stus[i].Information();
        }
    }
}

/**
 * 定义学生类
 */
class Student{
    int number;
    int state;
    int score;

    public void Information(){
        System.out.println("number: " + number + " state:" + state + " score:" + score);
    }
}

4.6 再谈方法

4.6.1 方法的重载

重载的概念:

在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可

重载的特点:

与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。

总结:“两同一不同”:相同类中,相同方法名

参数列表不同:参数个数不同,参数的类型不同

方法的重载与权限修饰符,返回值类型,形参名都没有关系

如何确定调用了一个类的那个方法?

  • 通过方法名
  • 通过形参列表的个数和类型

重载实例

/**
 * @author Jinxin Li
 * @create 2020-07-29 20:37
 * 定义三个重载方法max(),
 * 第一个方法求两个int值中的最大值,
 * 第二个方法求两个double值中的最大值,
 * 第三个方法求三个double值中的最大值,并分别调用三个方法。
 */
public class HomeWork2 {
    public static void main(String[] args) {
        HomeWork2 test = new HomeWork2();

        System.out.println(test.max(1, 2));
        System.out.println(test.max(0.5, 8.7));
        System.out.println(test.max(0.7, 10.9, 6.8));
    }

    public int max(int m, int n){
        return m > n ? m : n;
    }

    public double max(double m, double n){
        return m > n ? m : n;
    }

    public double max(double m, double n, double l){
        return  m > n ? (m > l ? m : l) : (n > l ? n : l);
    }
}

4.6.2 对象的使用:匿名对象的使用

我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。

如:new Person().shout();

使用情况

如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。

我们经常将匿名对象作为实参传递给一个方法调用。

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-29 19:00
 * 匿名调用
 */
public class ConcealableNameTest {
    public static void main(String[] args) {
        new CallPhone().PhoneCalling();//匿名调用
    }
}

class CallPhone{
    int PhoneNumber = 12231;
    public void PhoneCalling(){
        System.out.println(PhoneNumber);
    }
}

4.6.3 可变个数的形参

测试java中方法的可变形参的使用

public void sum(int i){
    "普通形参的方法".sout
}
public void sum(int ...i){//可变形参的形式
    "可变形参的方法".sout
}

格式:数据类型 … 参数名

说明:

  • 在调用可变形参的方式时,可以给可变形参赋值的参数个数为:0个,1个,2个,…
  • 在main函数进行调用时,优先寻找存在指定参数个数的重载方法进行代入,但是一般如果已经存在可变形参的方法,就不会继续编写其重载的其他方法
  • 可变形参的方法在同一个类中,能够与相同方法名的多个方法构成重载
  • 可变形参的方法a 与 参数同类型的数组的形参的方法b,不能在一个类中同时声明,不会发生重载
//可变形参与数组
public void sum(int ...arr){
    System.out.println("可变形参的方法");
    for(int i = 0; i < arr.length;i++){
        System.out.println(arr[i]);
    }
}

public void sum (int[] arr){
    for(int i = 0;i < arr.length;i++){
        System.out.println(arr[i]);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gWyaClDO-1596345581922)(images/image-20200731182018027.png)]

可以看到其实可变个数的形参其实在编译器中被视为数组,靠的是数组来进行处理不同个数的形参

  • 可变形参必须在参数列表的最后。(编译器不明白你少个)

其实可以理解,因为在参数列表中,如果你写在前面,则编译器无法判断你写在后面的数是否属于你的可变形参的数量。

  • 可变形参要求只有一个可变形参

4.6.3.0 数组的println(char[])

一般如果对于数组而言,数组打印的是地址


public class PrintArrayTest {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3};
        System.out.println(arr);//地址值

        char[] arr1 = new char[]{'a','b','c'};0.00
        System.out.println(arr1); //abc

        System.out.println(123.0);
        System.out.println("abc");
    }
}

而在println中存在char[] 数组类型,println能够直接打印

4.6.4 变量间的传递规则

基本数据类型 传递的是基本数据类型变量保存的数据值。

引用数据类型 传递的是引用数据类型变量保存的地址值。

形参:方法声明时,小括号内声明的参数

实参:方法调用时,实际传递过去的参数

<1> 方法的参数传递机制:值传递机制

交换1:方法内交换两个变量的值

public static void main(String[] args){
    int m = 10;
    int n = 20;
    System.out.println("m = " + m);
    System.out.println("n = " + n);
   
    //交换两个变量的值
    int temp = m;
    m = n;
    n = temp;
    
    System.out.println("m = " + m);
    System.out.println("n = " + n);
}

上面可以看出在main方法中,直接对参数进行

交换2:调用方法,实现变量的交换

//接上述程序
public class ValueTransferTest1 {
    main;
    int m = 10;
    int n = 20;
    
    //定义新的变量
    valueTransferTest1 test = new ValueTransferTest1();
    test.swap(m,n);
    
    sout.m;
    sout.n;
}

//定义交换的方法
public void swap(int m, int n){
    int temp = m;
    m = n;
    n = temp;
}
//结果并没有转换过来
  • 可以得出在上述方法中,参数并没有被转换过来
  • 在方法的使用中,对于基本数据类型来讲,将实参定义传入到方法中,与本来定义的变量不同,仅仅将数值传递过去,完全属于两套变量

例题3 方法的参数传递

package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-31 11:14
 */
public class ValueChange {
    public static void main(String args[]) {
        ValueChange test = new ValueChange();//创建新对象
        test.first();
    }
    public void first() {
        int i = 5;
        Value v = new Value();
        v.i = 25;
        second(v, i);
        System.out.println(v.i);
    }
    public void second(Value v, int i) {
        i = 0;
        v.i = 20;
        Value val = new Value();
        v = val;
        System.out.println(v.i + " " + i);
    }
}

class Value {
    int i = 15;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZlsXGnUd-1596345581924)(images/image-20200731200528077.png)]

4.6.4对象数组指定索引进行交换

/**
     * 交换stus数组中指定的index1和index2位置上的元素
     * @param stus
     * @param index1
     * @param index2
     */
    private void swap(Student[] stus,int index1,int index2){
        Student tempStudent = stus[index1];
        stus[index1] = stus[index2];
        stus[index2] = tempStudent;
    }

    //错误的写法
    public void swap(Student s1,Student s2){
        Student tempStudent = s1;
        s1 = s2;
        s2 = tempStudent;
    }

4.6.5 递归(recursion)

一个方法体内调用它自身

递归方法:一个方法体内调用它自身。

  • 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
  • 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
import java.io.File;

/**
 * @author shkstart
 * @create 2020-07-31 11:58
 *
 * 递归方法:一个方法体内调用它自身。
 * 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
 * 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
 */
public class RecurionTest {
    public static void main(String[] args) {
        RecurionTest test = new RecurionTest();
        System.out.println(test.getSum(100));
        System.out.println(test.getSum1(100));

        System.out.println(test.f(10));
    }

    //计算1-100自然数的和,并返回
    public int getSum(int num){
        int sum = 0;
        for(int i = 1;i <= num;i++){
            sum += i;
        }
        return sum;
    }

    //递归举例1:计算1-100自然数的和,并返回
    public int getSum1(int num){
        if(num == 1){
            return 1;
        }else{
            return num + getSum1(num - 1);
        }
    }

    //递归举例2:n!
    public int multiply(int num){
        if(num == 1){
            return 1;
        }else{
            return num * multiply(num - 1);
        }
    }

    //递归举例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
    //其中n是大于0的整数,求f(10)的值。
    public int f(int n){
        if(n == 0){
            return 1;
        }else if(n == 1){
            return 4;
        }else{
            return 2*f(n - 1) + f(n - 2);
        }
    }
    //递归举例4:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),
    //其中n是大于0的整数,求f(10)的值。
    public int func(int n){
        if(n == 20){
            return 1;
        }else if(n == 21){
            return 4;
        }else{
            return func(n + 2) - 2 * func(n + 1);
        }
    }

    //递归举例5:斐波那契数列(Fibonacci)
    //  1  1  2  3  5  8  13  21  34  55
    //  规律:一个数等于前两个数之和: f(n) = f(n - 1) + f(n - 2)

    //递归举例6:汉诺塔

    //递归举例7:遍历指定文件目录下的所有文件名
    public void printFileName(File dir){
        if(dir.isFile()){//是文件
            System.out.println(dir.getAbsolutePath());
        }else{//是文件目录
            File[] files = dir.listFiles();
            for(int i = 0;i < files.length;i++){
                printFileName(files[i]);
            }

        }
    }
    //拓展:计算指定文件目录的大小、删除指定的文件目录

    //递归举例8:快速排序
}

4.7 面向对象特征之一:封装与隐藏、

private体现封装性

4.7.1 封装性的引入

我们在创建了类的对象以后,可以通过"对象.属性"的方式给对象的属性赋值。

此时,对象的属性的赋值需要满足相应的数据类型和取值范围。在此之外,实际问题中可能还有其他的一些限制条件。(比如:legs要求是正数、偶数、0~30)

那么该如何添加限制条件呢?

给属性提供公共(public)的setXxx()方法用于设置属性的值。在方法内,可以添加额外的限制条件。

给属性提供公共(public)的getXxx()方法用于获取属性的值。在方法内,可以添加额外的限制条件。

同时,将类中的属性xxx,设置为私有的(private)

public class AnimalTest {
    public static void main(String[] args) {
        Animal a1 = new Animal();
        a1.name = "大黄";
//        a1.age = 5;
        a1.setAge(5);
//        a1.legs = -4;
        a1.setLegs(4);

//        System.out.println(a1.legs);
        System.out.println(a1.getLegs() + "!!!");

        a1.info();
        a1.eat();
//        a1.sleep();
    }
}

class Animal{//动物类
    //属性
    String name;
    private int age;
    private int legs;//腿的个数

    //方法
    //给legs属性赋值的方法
    public void setLegs(int l){
        if(l >= 0 && l % 2 == 0 && l <= 30){
            legs = l;
        }else{
            System.out.println("输入的数据不合法!");
        }
    }

    //获取legs属性值的方法
    public int getLegs(){
        return legs;
    }

    //提供关于age属性的set和get方法
    public void setAge(int a){
        age = a;
    }

    public int getAge(){
        return age;
    }


    public void eat(){
        System.out.println("动物进食");
        sleep();
    }

    private void sleep(){
        System.out.println("动物休息");
    }

    public void info(){
        System.out.println("name = " +name + ", age = " + age + ", legs = " +legs);
    }
}

4.7.2 封装性的体现

封装性的体现:体现为4种不同的权限:(从小到大)private < 缺省 < protected < public

体现之一:私有化类的属性,提供公共的get和set方法,用于获取和设置此属性的值。

体现之二:私有化类的方法,表示此方法仅在类内部使用。不会暴露给类外使用。

体现之三:单例模式(涉及到私有化构造器)(后面讲)

通过使用4种不同的权限修饰类及类的内部结构,从而体现被修饰的结构在调用时的可见性的大小!

三 4种不同的权限修饰符:private < 缺省 < protected < public

4种不同的权限修饰符可以用来修饰类的内部结构:属性、方法、构造器、内部类。

修饰类的话,仅能使用2种权限:缺省 、 public

修饰符 类内部 同一个包 不同包的子类 同一个工程
private Yes
(缺省) Yes Yes
protected Yes Yes Yes
public Yes Yes Yes Yes

练习Person

创建程序,在其中定义两个类:Person和PersonTest类。定义如下:

用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。

在PersonTest类中实例化Person类的对象b,

调用setAge()和getAge()方法,体会Java的封装性。

Person
-age:int
+setAge(i: int) +getAge(): int
package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-31 16:05
 */
public class PracticeAge {
    public static void main(String[] args) {
        Person b = new Person();
        System.out.println(b.getAge());

        b.setAge(1);
        System.out.println(b.getAge());
        b.setAge(23);
        System.out.println(b.getAge());
    }

}
class Person{
    private int age;
    public void setAge(int i){
        if(i >= 0 && i <= 130){
            age = i;
        }
    }
    public int getAge(){
        return age;
    }
}

4.8 类的成员之三 构造器(构造方法)

构造器的结构 修饰器+类名 不需要声明返回类型,因为不属于方法

构造器的作用

1.创建类的对象

2.给对象的属性初始化赋值

关于构造器的说明

构造器的默认权限取决于类的权限

如果没有显式声明类的构造器的话,则系统会默认提供一个空参的构造器

构造器声明格式:权限修饰符 类名(形参列表)

Person{
    String name;
    int age;
}

类中可以声明多个构造器,彼此之间构成重载

如果用户一旦显式的声明了类的构造器,则系统不再提供参数的构造器

类中一定会声明构造器

//在前面定义的Person类中添加构造器,利用构造器设置所有人的age属性初始值都为18。
package AfterClass;

/**
 * @author Jinxin Li
 * @create 2020-07-31 16:05
 */
public class PracticeAge {
    public static void main(String[] args) {
        Person b = new Person(9);
        System.out.println(b.getAge());
        b.setAge(23);
        System.out.println(b.getAge());
    }

}
class Person{
    private int age;
    public Person(int c){//声明构造器,不要返回值类型
        age = c;
    }
    public void setAge(int i){
        if(i >= 0 && i <= 130){
            age = i;
        }
    }
    public int getAge(){
        return age;
    }
}

A Java面向对象(预习教程)

A.1 继承

就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

//类的继承格式
class 父类{
}
class 子类 extends 父类{
}

A.2 构造器

子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。

如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。

A.3 关键字 extends implements super this final

extends

在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。

public class Animal { 
    private String name;   
    private int id; 
    public Animal(String myName, String myid) { 
        //初始化属性值
    } 
    public void eat() {  //吃东西方法的具体实现  } 
    public void sleep() { //睡觉方法的具体实现  } 
} 
 
public class Penguin  extends  Animal{ 
}

implements

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}

super与this关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

this关键字:指向自己的引用。

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

final关键字

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IrAdD4SC-1596345581926)(images/image-20200730101844028.png)]

A.4 重写(Override)与重载(overload)

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。

重载是随机应变

A.5 多态

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

A.6 抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。

父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。

在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口

Java 包(Package)

为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。

包的作用

  • 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
  • 如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
  • 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。

04-1 面向对象编程(上)

4.9 拓展知识 JavaBean

UML类图

4.10 构造器给对象赋值的位置

  1. 默认赋值
  2. 显式赋值
  3. 构造器中赋值
  4. 创建了对象以后,通过“对象,属性”或者对象。方法“的方式给属性赋值

赋值的先后顺序:

1,2,3,4;

4.11 this关键字的使用

可以调用属性,方法,构造器

我们在类的方法或类的构造器中,可以调用当前类中的属性跟方法

都常都省掉this

在特殊情况下this不可以省-同名

可以在类的构造器中显式的声明this构造器

this可以调用其他构造器

this()

为什么使用关键字?

this调用属性,方便给形参命名

当方法中定义的局部变量,包含形参

this调用构造器

new+构造器才调用对象

其他构造器是初始化一些操作

this必须声明在首行

在一个类的构造器中最多只能声明一个

谁调用方法,谁是this

4-10 关键字package

package放在源文件的开头

声明包名,属于标识符的一种,

在定义时需要满足标识符的命名规则,规范,见名知意

包名全小写

每“."一次,就代表一层文件目录

同一个包内不能有同名的类,接口

4-11 关键字 import导入

1.我们可以在package包声明和java类之间声明导入结构的

2.我们可以在当前类中,使用其他包下的结构

特例

lang包下不用导入,就可以使用

当使用包下的文件,达到五个时,会变成.*的方式,表示可以导入java.util的所有结构

子包,lang包下子包也需要导入

第五章 面向对象编程(中)

1.OOP特征二:继承性

1.1好处

1.2 格式

说明:

直接父类。间接父类

2.方法的重写

重载,两同一不同

测试方法的重写

(override、overwrite)

子类可以更大

权限应该更大

3.四种访问权限修饰符

4.关键字 super

你可能感兴趣的:(java基础,java)