目录
5、java语言中包括两种数据类型: - 基本数据类型: - 引用数据类型
写一个测试程序:有两个文件:Product 和ProductTest
例子3: 三个文件:House类、Person类、Test类
2、构造方法存在的意义是:通过构造方法的调用,可以创建对象。
第四章 this关键字、static关键字、继承、方法的覆盖
一、
1、Java的加载与执行:一个完整的java程序。
* Java开发的整个生命周期,包括两个重要的阶段,分别是:编译阶段和运行阶段。
* 编译生成的程序被称为:字节码程序。编译生成的文件是:xxx.class文件
* 编译和运行可以在不同的操作系统中完成。
* 程序员在xxx.java文件中编写源代码,源代码必须符合java的语法,这些源代码就是高级语言。
存放源代码的文件被称为源文件。
* 过程:
编译期:【在windows环境中完成】
- 安装JDK,配置环境
- 在硬盘的某个位置创建一个xxx.java源文件
- 打开源文件,在该文件当中编写符合java语法的源程序,然后保存。
- 使用JDK中自带的【javac.exe】命令对以上的java源程序进行编译。
(javac是一个java编译工具/命令。)
* 编译通过:说明语法没有问题
- 在硬盘上生成一个或者多个字节码文件【xxx.class】
* 编译失败:说明源程序某个位置不符合java语法格式。
* javac怎么使用?
编译的语法格式: 打开DOS命令窗口,输入:javac 源文件路径
注意:
- 源文件路径可以是绝对路径,也可以是相对路径。
- 编译之后,其实java源文件删除不会影响程序的执行。
- 最好不要将java源文件删除,因为程序最终运行效果不是预期效果的时候,需要重新修改java源代码,然后进行重新编译生成全新的class字节码文件,再重新运行字节码程序。
运行期:【可以不在windows中完成,可以换一个操作系统,但前提是该操作系统中已经安装java的运行时环境】
- 打开命令窗口,在命令窗口中使用【java.exe】命令运行java程序。
语法格式:java 类名
注意:java这个命令使用的时候,java命令后面不是文件的路径,(javac命令后面是文件的路径)。必须是一个“类名”,并且不加“.class”。
例如:
java Hello
java Student
java User
java Product
- 以上程序的执行原理:
* java.exe命令执行会启动:【JVM】
* JVM启动之后,马上启动“类加载器:【Class Loader】”
* ClassLoader负责去硬盘的“某个位置”上搜索“类名.class”字节码文件。
* 找不到这个.class文件,一定会出现程序异常现象。
* 找到了这个.class文件之后将.class文件装载到JVM中。
* JVM将.class文件转换成"二进制",操作系统可以直接识别二进制,
* 操作系统执行二进制码和底层的硬件平台进行交互。
2、什么是类名?
* 假设硬盘上有一个文件,叫做Hello.class,那么类名就叫做:Hello
* 假设硬盘上有一个文件,叫做Student.class,那么类名就叫做:Student
* 假设硬盘上有一个文件,叫做User.class,那么类名就叫做:User
* 假设硬盘上有一个文件,叫做Product.class,那么类名就叫做:Product .....
3、开始第一个java程序的开发
* JDK下载
* JDK安装
- 只安装了JDK,独立的JRE没有安装
- JDK、JRE、JVM的关系:依次包含的关系
JDK目录的介绍:
JDK/bin:该目录下存放了很多命令,如javac.exe(编译)、java.exe(运行)
* 在硬盘的某个位置上新建一个java源文件:HelloWorld.java
* 在HelloWorld.java文件中编写源代码
* 打开dos命令窗口,使用javac命令进行编译:
javac 源文件路径
* 出现以下错误:
C:\Users\Administrator>javac
'javac' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
* 怎么解决?
第一种方案:切换到javac.exe文件所在的目录,这个时候使用javac.exe不会出问题,但是这种方式比较麻烦。
第二种方案:配置环境变量path
原理:windows操作系统在查找某个命令的时候是怎么查找的?
* 首先会从当前目录下找这个命令
* 当前目录下不存在这个命令的话,会去环境变量path指定的路径当中查找该命令。
* 还是找不到则出现错误提示信息。
- path环境变量隶属于windows操作系统,和java无关,这个环境变量主要用来指定命令的搜索路径。
环境变量怎么配置?
计算机 --> 点击右键 --> 属性 --> 高级系统设置 --> 环境变量
环境变量配置包括用户级别和系统级别
任何一个环境变量都有变量名和变量值,例如path环境变量:
变量名是:path
值:路径【多个路径之间必须采用分号隔开,而且要求分号必须是半角分号】
path=C:\Program Files (x86)\Java\jdk1.7.0_75\bin;otherpath;otherpath.....
编译1【绝对路径】:D:\course\JavaProjects>javac D:\course\JavaProjects\02-JavaSE\day01\HelloWorld.java
编译2【相对路径】:D:\course\JavaProjects>javac 02-JavaSE\day01\HelloWorld.java
编译3【相对路径】:D:\course\JavaProjects\02-JavaSE\day01>javac HelloWorld.java
* 运行:
- 首先测试java命令是否可用
- 使用方式:java 类名
注意:
必须将路径切换到“D:\course\JavaProjects\02-JavaSE\day01”目录下
再执行:java HelloWorld
- D:\course\JavaProjects\02-JavaSE\day01>java HelloWorld
Hello World!
4、打开DOS命令窗口,执行java HelloWorld,执行原理?
* java.exe 命令会启动 JVM
* JVM 启动之后会启动类加载器ClassLoader
* ClassLoader会在硬盘上的某个位置搜索HelloWorld.class字节码文件
* 找到该文件则执行
* 找不到该文件则报错
疑问:ClassLoader是在哪个位置上搜索HelloWorld.class字节码文件的?
* 默认情况下,ClassLoader从当前路径下加载xxx.class字节码文件
* 当然,也可以让ClassLoader去某个指定的路径下加载字节码文件,这时需要配置环境变量classpath
* classpath环境变量属于java语言中的环境变量,不属于windows操作系统【PATH环境变量属于操作系统】
* classpath是给ClassLoader类加载器指路的。
* 设置这样的环境变量:classpath=D:\course\JavaProjects\02-JavaSE\day02
- 打开dos命令窗口在任意位置,都可以执行:java HelloWorld
* classpath环境变量没有配置的话,类加载器默认从当前路径下找字节码文件,
当classpath环境变量配置为某个指定的路径之后,类加载器只去指定的路径当中加载字节码文件。
* 综上所述,环境变量classpath不再配置,这样类加载器会自动从当前路径下加载class字节码文件。
所以,每一次执行.class程序的时候,需要在DOS命令窗口中先切换到.class字节码文件所在的路径下。
然后运行。
* 当然,classpath也可以这样配置:classpath=.
注意:
路径中“..”表示上级目录
路径中“.”表示当前目录
5、关于java源程序当中的注释:
* 什么是注释?注释的作用是什么?
- 出现在java的源程序当中,对java源代码的解释说明
- 注释不会被编译到.class字节码文件当中
- 一个好的开发习惯应该是多编写注释,这样程序的可读性比较强。
* java中的注释怎么写呢?
- 单行注释
//单行注释,只注释当前行
- 多行注释
/*
多行注释
多行注释
.....
*/
- javadoc注释
/**
* javadoc注释
* javadoc注释
*/
注意:这种注释是比较专业的注释,该注释信息会被javadoc.exe工具解析提取并生成帮助文档。
6、对HelloWorld程序进行解释:
需要记忆:
* public
* class
* static
* void
* 类体是什么
* 方法体是什么
* 类体中不能直接编写java语句【除声明变量之外】
* 一个java语句必须以“;”结束
* 方法体中可以编写多条java语句
* 主方法是程序的入口,固定写法,SUN规定的。
Public class HelloWord{ //定义一个公开的类,起名叫HelloWord
//里面的叫做类体
public static void main(string [] args){ //定义一个公开的静态的主方法
//方法体
//方法体中可以编写多条java语句,以分好结尾
System.out.printIn("HelloWord!"); //向控制台输出消息
}
}
7、public class 和 class的区别:
* 一个java源文件当中可以定义【多个class】
* 一个java源文件当中【public的class不是必须的】
* 一个class会定义生成一个xxx.class字节码文件
* 一个java源文件当中定义公开的类【(public class)】的话,只能有一个,并且【该类名称必须和java源文件名称一致】。
也就是说只能一个public class,且如果定义了public class K,这个文件名也要是k.java。
* 每一个class当中都可以编写main方法,都可以设定程序的入口,想执行B.class中的main方法:【java B】, 想执行X.class当中的main方法:【java X】
* 注意:当在命令窗口中执行java Hello,那么要求Hello.class当中必须有主方法。没有主方法会出现运行阶段的错误:
D:\course\JavaProjects\02-JavaSE\day02>java Hello
错误: 在类 B 中找不到主方法, 请将主方法定义为:
public static void main(String[] args)
第二章:Java语言基础
基本知识点
1、标识符
【自己起名字】的就是标识符,如类名,接口名,常量名等。
数字、字母、下划线、 $...组成,数字不能开头。
严格区分大小写。
关键字不能做标识符。
驼峰命名法,类名首字母大写,见名知意。
2、关键字
特殊含义的字符序列,如 public、class、static,关键字不做标识符。
3、字面值(就是数据)
10 12.3 true\false ‘A’ "A"
4、变量※
局部变量(在方法体中声明的变量)、成员变量(声明在类名之内,方法体之外的变量)
必须先声明再赋值。没有赋值的默认为0。
声明变量 int i,j=10;
变量有作用域,除了大括号 就不认识了。
5、数据类型(四大类八小种)
byte int short long float double boolean char
[-128~127] [true\false] [0~65535]
基本数据类型之间的相互转换规则
=》八种类型除了布尔型外都可以相互转换
=》小容量转大容量,称为自动类型转换
容量从小到大为byte<short<int<long<float<double
char<
=》大容量转小容量,称为强制类型转换
如果数据没有超过byte、short、char的数据范围,可以直接赋值给byte,short,char
不需要强制类型转换,但如果超过范围需要手动强制类型转换,会导致精度的损失。
大容量转小容量需要加强制类型转换符,不加的话程序过不去,就算过去了精度会损失。
=》byte、short、char混合运算时候,先转为int再运算。
=》多种数据类型混合运算,先转为容量大的类型,再运算。
6、 转义字符 \
转移字符出现在特殊字符之前,会将特殊字符转为普通字符
\n 换行符
\t 制表符
\' 普通的单引号
\\ 普通的反斜杠
\" 普通的双引号
7、运算符
* 算术运算符:+ - * / % ++ --
* 关系运算符:> < >= <= == != 解为布尔类型值
* 逻辑运算符:& | ! ^ &&(短路与) ||(短路或)
* 赋值类运算符:=
* 字符串连接运算符:+
* 三元运算符:布尔判断?表达式1 :表达式2
8、控制语句:
* 选择结构
- if、if..else
- switch
* 循环结构
- for
- while
- do..while
* 控制循环的语句
- break 表示整个循环结束,不执行了
- continue 表示此值的循环结束,进行下次循环
/*
编写for循环找出1~100中所有的素数
*/
public class ForTest09
{
public static void main(string[] args){
//先编写程序,验证7是否为素数
/*思路
7/1 不需要
7/2 7%2!=0
7/3 7%2!=0
7/4 7%2!=0
7/5 7%2!=0
7/6 7%2!=0
7/7 不需要
*/
for (i =2; i<=100;i++){
boolean issushu =true;//这是标记,默认将i看做素数,这种用法必须会用
for (int j =2;j<i ;j++){
if (i%j==0){
issushu= false;
break;
}
}
system.output.println(issushu ? i +"是素数" :i +"不是素数");
}
}
}
/*升级版:加入统计机制 ,每八个换一行
编写for循环找出1~100中所有的素数
*/
int count =0;
for (i =2; i<=100;i++){
boolean issushu =true;//这是标记,默认将i看做素数,这种用法必须会用
for (int j =2;j<i ;j++){
if (i%j==0){
issushu= false;
break;
}
}
if (issushu){
system.out.println(i + "");
count ++;
if (count%8==0){
system.output.println();
}
}
}
方法
/*以下程序不使用“方法”,有什么缺点?*/
public class MethodTest01
{
public static void main(string[] args){
//需求1:计算10和20的和,并将结果输出
int aa =10;
int bb=20;
int c =a+b;
system.out.println(a + "+"b+"="+c);
//需求1:计算10和20的和,并将结果输出
int aa =999;
int bb=666;
int c =a+b;
system.out.println(a + "+"b+"="+c);
}
}
/*以下程序使用“方法”,有什么优点?*/
public class MethodTest02
{
public static void main(string[] args){
//计算两个int类型数据的和
MethodTest02.sumInt(10,20);
MethodTest02.sumInt(666,888);
MethodTest02.sumInt(111,222);
//单独定义一个方法
public static void sumInt(int a ,int b){
int c =a+b;
system.out.println(a + "+"b+"="+c);
}
}
以上两个需求其实是一个需求,只是参加的数据不同。
缺点:不灵活,繁琐,同样的操作多次写。代码没有重复使用【调用invoke】。
应该在java中有这样的机制:某个功能代码只需要写一遍。使用这个功能,只需要给这个功能传递具体数据。
这个功能完成后返回一个最终的结果.实现重复利用性。这就是【方法】。
1、方法(Method)
本质是:是一段代码片段,这个片段可以完成某个特定的功能,且可以重复使用。
方法定义在类体中,在一个类中可以定义多个方法,方法位置随意无先后之分。
方法体中不能在定义方法。 方法体由java语句构成,方法体中的代码自上而下顺序执行。
方法在C语言中叫 函数function。
2、方法怎么定义?语法结构
[修饰符列表] 返回值类型 方法名(形参列表){
方法体;
}注:1、修饰符列表:
*可选性,不是必须的,目前统一为public static,关键字不做标识符。
*方法的修饰符列表中有“static关键字”的话,怎么调用?
类名.方法名(实参列表);
2、返回值类型
*什么是返回值:一个方法是可以完成某个特定功能,这个功能结束之后最终多是要返回最终的执行结果
这个执行结果可以是具体数值,只要是数据一定有类型,这个类型就是返回值类型。
*返回值类型: java任意类型都可以,byte,short,int,boolean,char,string,void...
也可能方法执行结束后,没有返回值,必须编写void类型。return;
*返回值的类型和前面定义的返回值类型一致。
*只要带有return关键字的语句执行,return语句所在的方法结束。3、方法名:只要是合法的标识符就行。见名知意。最好是动词。
4、方法体:必须由大括号,每句由分号结束。
5、形参:局部变量:int a ;
多个形参以逗号隔开。
形参中起决定作用的是形参的数据类型(int double...),形参名字就是局部变量的名字。
实参列表和形参列表必须满足数量相同,类型对应。
6、方法怎么调用?
方法只是定义,不调用的话是不会执行的。只有在定义的时候才会执行。
语法规则:(犯法的修饰列表中要有static)
类名.方法名(实参列表);
以下是示例介绍:
//public表示公开的,class表示定义类,MethodTest03类名
public class MethodTest03{
//定义一个公开的类,起名为MethodTest03,由于是公开类,所以源文件名必须为MethodTest03
//类体
//类体中不能直接编写java语句,除了声明变量之外
//方法出现在类体中
//static表示静态,void表示方法执行结束后,不返回任何数据。
//main是方法名:主方法
//string[]是一种引用数据类型 args是一个局部变量的变量名
//所以以下只有args这个局部变量名可以随意写.
//主方法就是需要这样固定编写,这是程序入口。
public static void main(string[] args){
//这里的程序一定会执行
//main方法是JVM负责调用的,是入口位置
//从这里开始作为起点开始执行程序
//既然这样,我们可以在这里编写java语句来调用其他方法,如下调用了sumInt方法。
MethodTest03.sumInt(10,20);
//一个方法可以重复使用,重复调用。
int a =100;
MethodTest03.sumInt(a,300);
//再调用一次
int k=200;
int f=230;
MethodTest03.sumInt(k,f);
}
//自定义方法,不是程序的入口
//方法作用:计算两个int的和。不要求返回数据结果,但要求将结果直接输出到控制台
//修饰符列表:public static
//返回值类型:void
//方法名:sumInt
//形参列表:(int a,int b)
//方法体:求和后输出结果
public static int sumInt(int a ,int b){//定义一个sumInt方法
System.out.println(a+"+"+b+"="+(a+b));
}
public static void s(int a ,int b){
}
}
public static ??? 方法名(???){
???;
}
???的位置是要着重思考的地方
/*方法调用:
方法修饰符列表中有static时候,方法调用:类名.方法名(实参);
什么时候类名可以省略呢?
*/
public class MethodTest06{
public static void main(string[] args){
//调用方法(完整的方式)
MethodTest06.sumInt(10,20);
//方法修饰符列表中有static时候,调用方法时可以省略类名么?
s();
//调用其他类【不是本类中】的方法
不行!没写类名,它只在当前类中寻找
doother(); //报错
}
public static int sumInt(int a ,int b){
System.out.println(a+"+"+b+"="+(a+b));
}
public static void s(int a ,int b){
}
class A {
public static void doother(){
System.out.println("A method invoke!");
}
}
}
3、深入return语句:
/*分析以下程序的输出结果*/
/*
1、方法的返回值类型不是void的时候。
要求方法必须保证百分百执行“return 值“,这样的语句来完成值的返回。
要求将最终的计算结果返回给调用者。
2、方法定义的类型要和return类型相同。
3、一个方法有返回值时,当我们调用这个方法时,方法返回了一个值
对大部分调用者来说,这个返回值可以选择接受,也可以不接受
但是大部分是接收的。
*/
public class MethodTest08{
public static void main(string[] args){
//调用方法
divide1(10,5);//这里没有接收这个方法的返回数据
//下面接收一下
//采用变量接收
//变量的数据类型需要和返回值类型相同,或可以自动类型转换
//boolean b=divide1(10,5);//编译报错,类型不兼容
int i= divide1(10,5);//等号右边先执行
System.out.println(i);
long x =divide1(10,3);
System.out.println(x);
System.out.println(divide1(10,3));
}
public static int divide1(int a,int b){
}//报错,缺少返回语句
public static int divide2(int a,int b){
return;
}//报错,缺少返回值
public static int divide3(int a,int b){
return a/b;
}//正确
}
/*带return关键字的java语句只要执行,所在方法执行结束
在同一个作用域中,return语句下面不能写其他代码,因为执行不到,会编译报错*/
public class MethodTest08{
public static void main(string[] args){
}
public static int m(){
int a=10;
if(a>3){
return 1;
}
}
上面的代码能够运行通过?
不能,if语句可能判断为false,此时没有return,可以加个else条件
也可以:
public class MethodTest08{
public static void main(string[] args){
}
public static int m(){
int a=10;
if(a>3){
return 1;
}
return 0;
}
/*返回值类型是void的方法当中使用return;语句*/
对于结果类型为void时,无法返回值,
可以加个ruturn;
/*方法中的内存是如何分配的?如何变化?*/
public class MethodTest11
{
public static void main (string[] args){
}
}
第三章:面向对象
1、 面向过程和面向对象的区别
面向过程:主要关注点是:实现的具体过程,因果关系【集成显卡的开发思路】
* 优点:对于业务逻辑比较简单的程序,可以达到快速开发,前期投入成本较低。
* 缺点:采用面向过程的方式开发很难解决非常复杂的业务逻辑,另外面向过程的方式导致软件元素之间的“耦合度”非常高,只要其中一环出问题,整个系统受到影响,导致最终的软件“扩展力”差。另外,由于没有独立体的概念,所以无法达到组件复用。
面向对象:主要关注点是:主要关注对象【独立体】能完成哪些功能。【独立显卡的开发思路】
* 优点:耦合度低,扩展力强。更容易解决现实世界当中更复杂的业务逻辑。组件复用性强。
* 缺点:前期投入成本较高,需要进行独立体的抽取,大量的系统分析与设计。
- C语言是纯面向过程的、C++半面向对象、Java纯面向对象
- 现在出现的一些新的编程语言多数都是面向对象的。人在认识现实世界的时候以面向对象的方式。
- 面向对象更符合人的思维方式。
2、 面向对象的三大特征: 封装、 继承、多态。
所有面向对象的编程语言都有这三大特征。
采用面向对象的方式开发一个软件,生命周期当中:【整个生命周期中贯穿使用OO面向对象方式】
* 面向对象的分析:OOA
* 面向对象的设计:OOD
* 面向对象的编程:OOP
3、 类和对象的概念
* 什么是类?
- 类在现实世界当中是不存在的,是一个模板,是一个概念。- 类代表了一类事物。
- 在现实世界当中,对象A与对象B之间具有共同特征,进行抽象总结出一个模板,这个模板被称为类。
* 什么是对象?
- 对象是实际存在的个体。现实世界当中实际存在。- 代表了某个具象事物。
* 描述一下整个软件开发的过程:
* 程序员先观察现实世界,从现实世界当中寻找对象
* 寻找了N多个对象之后,发现所有的对象都有共同特征
* 程序员在大脑中形成了一个模板【类】
* Java程序员可以通过java代码来表述一个类
* Java程序中有了类的定义
* 然后通过类就可以创建对象
* 有了对象之后,可以让对象直接协作起来形成一个系统。
* 类---->【实例化】---->对象
* 对象又被称为实例 instance
* 对象--【抽象】-->类
* 重点:
类描述的是对象的共同特征。 共同特征例如:身高特征
这个身高特征在访问的时候,必须先创建对象,通过对象去访问这个特征。
因为这个特征具体的某个对象上之后,值不同。有的对象身高1.80,有的对象身高2.80。
* 一个类主要描述什么信息呢?--描述: 状态 + 动作。
状态信息:名字、身高、性别、年龄-----> 一个类的属性
动作信息:吃、唱歌、跳舞、学习-------> 一个类的方法
* 类{
属性; //描述对象的状态信息
方法; //描述对象的动作信息
}
注意:
状态和动作当具体到某个对象上之后,发现最终的结果可能不一样。
对象和对象之间有共同特征,但是具体到对象之后有数据的差异。
4、 类的定义
语法结构:
[修饰符列表] class 类名{
属性;
方法;
}
学生类,描述所有学生对象的共同特征:【状态+行为】
学生对象有哪些状态信息:
* 学号【int】 * 名字【String】 * 性别【boolean】
* 年龄【int】【年龄是一个属性,年龄是一个数据,是数据就应该有数据类型】....
学生对象有哪些动作信息:
* 吃饭 * 睡觉 * 学习 ....
重点:属性通常是采用一个变量的形式来完成定义的。
如: int no; int age; String name; String address; boolean sex;
5、java语言中包括两种数据类型:
- 基本数据类型:
byte 、 short 、int、 long、 float、double、boolean 、 char
- 引用数据类型
String.class SUN提供的
System.class SUN提供的
Student.class 程序员自定义的
User.class 程序员自定义的
Product.class 程序员自定义的
Customer.class 程序员自定义的 ......
java语言中所有的class都属于引用数据类型。
6、对象
6.1对象的创建和使用-内存分析
通过一个类可以【实例化N个对象】。
有了类之后,如何实例化对象:new 类名();
new 是java语言中的一个运算符。 new 运算符的作用是创建对象,在JVM堆内存中开辟新的内存空间。
内存中有三块区域:栈内存、堆内存和方法区内存。
方法区内存:在类加载的时候,class字节码代码片段被加载到该内存当中。
栈内存(局部变量):方法代码片段执行的时候,会给该方法分配内存空间,在栈内存中压栈。
堆内存:new 的对象在堆内存中存储。
例子有OOTest01-03
具体在例子中讲解:
public class OOTest01{
public static void main(String[] args){
int i=10; //int是数据类型,i是变量名,10是字面值
Student s =new student();
//Student是提前写好的一个类,里面包含了Student的属性和方法
//Student是一个【引用数据类型】
//s是变量名,new student()是一个学生对象,s是一个局部变量【在栈内存中存储】
//什么是对象?new运算符在堆内存中开辟的内存空间称为对象
//什么是引用?引用是一个变量,不过这个变量中保存了另一个java对象的内存地址(有图可以借助理解,图在下面)
//java语言中,程序员不能直接操作堆内存,不像c语言
//程序员只能通过【引用】访问堆内存当中对象内部的实例变量
//访问实例变量的语法:
//读取数据:引用.变量名
//修改数据:引用.变量名=值
/*//读取:
//no、name、age、sex不能乱写, 是属性名
int stuNo=s.no;
String stuName=s.name;
int stuAge=s.age;
boolean stuSex=s.sex;
String stuAddr=s.addr;
System.out.println("学号="+stuNo);
System.out.println("姓名="+stuName);
System.out.println("年龄="+stuAge);
System.out.println("性别="+stuSex);
System.out.println("住址="+stuAddr);
*/
//也可以写成如下:
System.out.println("学号="+s.no);
System.out.println("姓名="+s.name);
System.out.println("年龄="+s.age);
System.out.println("性别="+s.sex);
System.out.println("住址="+s.addr);
//修改:
s.no=10;
s.name="bella";
s.age=20;
s.sex=true;
s.addr="北京";
System.out.println("学号="+s.no);
System.out.println("姓名="+s.name);
System.out.println("年龄="+s.age);
System.out.println("性别="+s.sex);
System.out.println("住址="+s.addr);
//再通过类实例化一个全新的对象
Student stu=new Student();
//System.out.println(Student.no);
//编译报错,no这个实例变量不能直接采用类名的方法访问,应该用引用
//因为no是实例变量,对象级别的变量,变量存储在java对象的内部,必须先有变量
//通过对象才能访问no这个实例变量,不能直接通过类名访问
//正确的是System.out.println(Stu.no);
}
}
局部变量在栈内存中存储,成员变量中的实例变量在堆内存的java对象内部存储,实例变量是一个对象一份。100个对象100份。
引用是一个变量,可以引用成员变量,也可以引用实例变量。变量包括局部变量和成员变量。
总结:
jvm(java虚拟机)主要包括三方面内存:分别是栈内存、堆内存、方法区内存。
堆内存和方法区内存各一个,一个线程一个内存。
方法调用时,该方法所需要的内存空间在栈内存中分配,称为压栈,方法结束后,该方法所属的内存释放,称为弹栈。
栈中主要存储的是方法体中的局部变量。
方法的代码片段和类的片段都存在方法区内存中,在类加载的时候,这些代码片段会载入。
在程序执行过程中,使用new创建的对象,存储在堆内存中。所以实例对象存在堆内存中。
变量分类:
局部变量(方法体中声明)
成员变量(方法体外声明)
实例变量(前面修饰符没有static)
静态变量(前面修饰符有static):静态变量存在方法区内存中。
三块内存中,变化最频繁的是栈内存,最先存储的是方法区内存,垃圾回收针对的是堆内存。
垃圾回收器:当堆内存中的java对象成为垃圾时,会被回收
(没有更多的引用指向时,成为垃圾。)(这个对象无法被访问)
另外:
1、静态变量和非静态变量的区别:
a.作用上来看:
静态变量是用来共享的,所有的对象都可以访问到。
非静态变量就是用来描述同一类事物的公共属性。
b.数量和存储的位置上:
静态变量存在静态方法区(数据共享区),并且只有一份数据。
非静态变量存在堆区中,对象有N个,数据就有N个。
c.生命周期:
静态变量是在随着类文件的加载而加载,随着类文件消失而消失。
非静态变量是随着对象创建而创建,随着对象的消失而消失。
2、static 修饰的方法使用需要注意的点:
a.静态方法可以用对象和类名调用。非静态方法只能用对象来调用。
b.静态方法是可以访问静态成员变量的,但是不能够访问非静态的成员变量。非静态方法可以访问任何的成员变量。
原因:有可能静态方法被调用了,但是对象还没有被创建出来,自然就没有成员变量。
c.静态方法中可以直接访问静态方法,但是不能访问非静态方法。非静态方法是可以访问静态方法。
原因:有可能静态方法被调用了,但是对象还没有被创建出来,又因为非静态方法只能由对象来调用,所以调用不了。
如果对象被创建出来,静态方法早就存在内存中了。
d.静态方法中是不允许出现this关键字 或者 super关键字的。
3、特点:静态的数据在就存在于非静态的数据存在内存中。
4、什么时候使用static来修饰方法?
当一个方法不需要直接访问非静态数据,这个时候就可以用static来修饰(定于工具类 如:arrays)。
6.2 对象的创建和使用-空指针异常
当不使用new关键字时,出现的问题。
6.3 对象的创建和使用-重申知识点及例子:
类应该怎么定义?
{修饰符列表 如public } class 类名{
属性;
方法 }
属性通常采用变量来表示,属性对应状态信息。(变量的数据类型:基本数据类型和引用数据类型)变量对应状态信息。
//定义商品类的例子
class Product{
//编号
int no;
//单价,浮点型
double price;
Student s=null;
}
注意 :我们很习惯把int double string......是数据类型,但是不习惯Student、User、Product,他们是引用数据类型。
另外我们也不习惯在类里面作为数据类型使用它们。为什么要在一个类里写一个Student s(Student 是一个类,s是一个引用)?
下面的例子进行讲解:
例1:有两个类:House类和Person类。
//人的类
public class Person {
String id;
String name;
String sex;
int phone;
}
//房子的类
public class House{
double pingmi;
//主人,
//String zhuren;
//我想知道更多信息,如这个人的身份证号,名字等,
//这里就不能写String应该写Person这个类名的数据类型。
Person zhuren;
//上面的Person是类(引用数据类型)里面有关于人的定义,zhuren是自己起名的变量
//关联关系:A 里面有一个B。这叫关联关系,【A对象中含有B对象的引用】
}
注意:第二段代码里面,定义房子的主人,普通的定义就是String zhuren;但是我想要知道主人的其他信息,如身份证号、名字、性别和电话,就要使用引用数据类型。如果不用引用数据类型。在House类里定义id name代码这个房子的id 和名字,而不是房子主人的信息。
写一个测试程序:有两个文件:Product 和ProductTest
public class Product {
float price;
int phone;
int productNo;
}
public class Person {
public static void main (String[] args){
// 現在我想知道某個商品的价
// 1、首先应该创建对象,创建商品对象
Product iPhone=new Product ();
// 2、访问实例变量的方法: 引用.变量名
// 访问实例变量有两个目的:一是读取二是修改
System.out.println("商品的编号是"+iPhone.productNo);
System.out.println("商品的单价是"+iPhone.price);
iPhone.productNo=111;
iPhone.price=6800;
System.out.println("商品的编号是"+iPhone.productNo);
System.out.println("商品的单价是"+iPhone.price);
}
}
运行主程序得出结果:
商品的编号是0
商品的单价是0.0
商品的编号是111
商品的单价是6800.0
例子3: 三个文件:House类、Person类、Test类
思路:先创建人对象,再创建房子对象,让房子有主人。
public class Test {
public static void main(String[] args) {
// 首先创建人对象
Person bella =new Person();
// 手动赋值
bella.name ="刁丽慧";
bella.id=370;
// (点后面的变量是Person类的变量,不是自己瞎写的)
// 再创建房子对象
House fangzi=new House();
fangzi.pingmi=100;
fangzi.jiage =1000;
// 让房子有主人
fangzi.zhuren=bella;
// 想知道房子的主人的名字
System.out.println("房子的主人的名字是"+fangzi.zhuren.name);
// 房子换主人了
// 1、首先创建新主人李四这个对象
Person lisi=new Person();
lisi.name="李四";
lisi.id=110;
//房子的主人这个属性变了
fangzi.zhuren=lisi;
// 房子现在的主人是谁?
System.out.println("现在房子的主人的名字是"+fangzi.zhuren.name);
}
}
public class House{
double pingmi;
float jiage;
Person zhuren;
}
public class Person {
String name;
int id;
}
结果是:房子的主人的名字是刁丽慧
现在房子的主人的名字是李四
例子4:
定义一个计算机类,笔记本电脑,笔记本电脑属性:品牌、型号、颜色。定义一个学生类,属性:学号、姓名、学生有一台笔记本。请编写程序,表示以上类,分别将类创建为对象,对象数量不变,然后让其中的一个学生去使用其中一台电脑,最后编译运行,并将整个执行过程采用图形方式描述出来。
public class SCTest {
public static void main(String[] args) {
// 创建学生对象和电脑对象
Computer diannao =new Computer();
diannao.pinpai="联想";
diannao.xinghao=777;
diannao.yanse="黑色";
Student bella=new Student();
bella.name="刁";
bella.xuehao=111;
bella.s=diannao;
System.out.println("bella 的电脑品牌是"+bella.s.pinpai);
// 这里怎么确定的是bella.s?--student类中有变量 s(Computer是数据类型)
}
}
public class Computer {
//品牌、型号、颜色
String pinpai;
int xinghao;
String yanse;
}
public class Student {
// 学号、姓名、学生有一台笔记本
int xuehao;
String name;
Computer s;
}
6.4 面向对象的封装性
安全性和重用性。
封装的步骤:属性私有化(private 声明变量)--》对外提供简单的入口以供访问:set和get方法(想改变某属性,就调用set方法,想要获取某方法的值,就要调用get方法)
set方法和get 方法的命名规范见下面例子中setAge和getAge:
package fengzhuangxing;
//用户类
public class User {
// 属性私有化
private int age;
// 私有化之后,数据只能在类中访问
// 解决办法:对外提供简单的入口以供访问:set和get方法
// public void setAge(int age){
// age=age;
// }
//报错
// 原因:java有就近原则,这里并没有给age赋值,等号左右的age都是局部变量
// 并没有指向前面的私有化age
// 怎么解决?
public void setAge(int a){
if(a<0){
System.out.println("年龄不合法");
return;
}
age=a; //把形参换个字母,即把a赋值给age
}
// get方法
public int getAge(){
return age;
// 注意没有形参,有返回值,且注意数据类型。
}
}
package fengzhuangxing;
public class UserTest1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
User yonghu=new User();
// 修改--引用名.方法名(实参)
yonghu.setAge(-100);
yonghu.setAge(100);
// 读取
System.out.println(yonghu.getAge());
}
}
注意1:set方法是为了修改,所以不用返回值,但需要一个形参。get方法是为了获取值,不需要传递形参,但需要返回值。
可以在封装的方法中设定一定的规则,如上面的a要大于零。
注意2:setter和getter方法没有static关键字。有static关键字修饰的方法的调用是:类名.方法名(实参);
没有static关键字修饰的方法的调用:引用.方法名(实参);
其实有一种不必自己亲自创建get和set的方法:
首先像这样定义好--》右键source--》generate setter and getter--全选--》ok
public class UserTest {
int age;
String name;
String address;
int id;
}
6.5 构造方法
- 构造方法又被叫做构造函数、构造器、constructor。
1、 语法结构:
[修饰符列表] 构造方法名(形参){
构造方法体;
}
- 回顾普通的方法语法结构:
[修饰符列表] 返回值类型 方法名(形参){
方法体; }
- 区别:对于构造方法来说,返回值类型不需要指定,并且不能写void。只要写上void,那么这个方法就变成了普通方法。
- 构造方法名必须与类名保持一致。
2、构造方法存在的意义是:通过构造方法的调用,可以创建对象。
-
构造方法怎么调用?
普通方法调用:方法修饰符中有static时:类名.方法名(实参列表)。方法修饰符中没有static时:引用.方法名(实参列表)
(即:只有静态变量才能用类来访问,非静态变量只能用对象来访问,类是不能访问的。)
构造方法调用:new 构造方法名(实参列表)
- 构造方法调用之后有没有返回值?--有返回值。
int i=10;--返回类型是 int。
User u=new User()--没有返回值的话,怎么赋值?返回类型是 User 。所以他不需要像普通方法一样写返回值类型。
每一个构造方法执行结束之后,都有返回值,但是这个“return 值”这样的语句不需要写。java自动返回。并且返回值类型是构造方法所在类型。
- public class User(){}---当一个类中没有定义任何构造方法,这个构造方法被称为缺省构造器。
- 当一个类显式的将构造方法定义出来了,那么系统则不再默认为这个类提供缺省构造器。所以建议开发中手动的为当前类提供无参数构造方法,因为无参数构造方法太常用了。
( 有参数的构造方法)
//pulic User ( ){
}
pulic User (int i ){
}
//此时在创建这个对象的时候会报错:
User u=new User();//报错
但是有了pulic User ( ){ }就不报错了
3、构造方法支持重载机制。
当一个类中编写多个构造方法,这多个构造方法,显然已经构成方法重载机制。只要构造方法调用,一定创建了对象。
public class User {
//无参数构造方法
public User(){
System.out.println("user 是默认构造方法!");
}
//有参数构造方法
public User (int i ){
System.out.println("int 类型的构造方法");
}
public User (String name ){
System.out.println("String类型的构造方法");
}
public User (int i ,String name ){
System.out.println("int 和String类型的构造方法");
}
}
public class constructor001 {
public static void main(String[] args) {
// 调用User类的构造方法来完成对象的创建
// 以下程序创建4个对象,只要构造函数调用,就会创建对象。并且在堆内存中开辟 了内存空间
User u1 =new User();
User u2 =new User(10);
User u3 =new User("bella");
User u4=new User(1,"bella");
}
}
运行结果:user 是默认构造方法!
int 类型的构造方法
String类型的构造方法
int 和String类型的构造方法
疑问:这个有参数的构造方法有什么用??--利用重载机制啊。
中期小结:
1、调用带有static的方法:类名.方法名();
在同一个类中可以写 方法名();
2、调用不带static的方法:引用.方法名();但是这个要先创建这个引用对象(调用无参数构造方法),即:
类名 引用=new 类名();
引用.方法名()
4、构造方法的另一个作用:
前面说了构造方法的作用一是创建对象,另一作用是给实例变量赋值(创建对象的同时,初始化实例变量的内存空间)。
成员变量之实例变量,属于对象级别的变量,这种变量必须先有对象才能实例变量。
实例变量没有手动赋值时,系统默认赋值,那么这个系统默认赋值是在什么时候完成的?
是在类加载的时候么?---不是。
因为类加载的时候只加载了代码片段,还没来得及创建对象,所以此时实例变量并没有初始化。
实际上,实例变量的内存空间是在构造方法执行过程当中开始的,完成初始化的。
系统在默认赋值时,也是在构造方法执行过程总完成的赋值。
实例变量默认值:
byte、short、int、long:0
float、double:0.0
boolean:false
引用数据类型:null
package gouzaofangfa;
//银行账户类
public class Account {
private String accountNo ;
private double balance;
// 无参数构造器
public Account(){
// 空
}
// 有参数构造器
public Account(String s){
accountNo=s;
// balance:0.0
}
// 有提供了一个有参数构造器
public Account(String s,double b){
accountNo=s;
balance=b;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
package gouzaofangfa;
public class gouzaofangfaText02 {
public static void main(String[] args) {
// 创建对象
Account act1=new Account();
System.out.println(act1.getAccountNo());
System.out.println(act1.getBalance());
// 调用有参数的构造方法
Account act2=new Account("FG110");
System.out.println(act2.getAccountNo());
System.out.println(act2.getBalance());
// 再调用有参数的构造方法
Account act3=new Account("Fnihao10",250.2);
System.out.println(act3.getAccountNo());
System.out.println(act3.getBalance());
// 给对象的属性赋值
}
}
上面例子分别调用了银行账号类中一个无参数构造器 和两个有参数构造器,结果如下:
null
0.0
FG110
0.0
Fnihao10
250.2
好消息:构造方法可以自动生成--source --generate constructor use file
6.6 参数传递
主要研究和学习的是方法在调用的时候,涉及到参数传递的问题,到底是怎么传递数据的呢?
值传递。
public class zhichuandi01 {
public static void main(String[] args) {
int i=10;
add(i);//add方法调用的时候,给add方法传递了一个参数i,到底传递的是什么?
System.out.println("main方法得到---》"+i); //10
}
public static void add(int i){
i++;
System.out.println("add方法得到--》"+i); //11
}
}
得到结果:
add方法得到--》11
main方法得到---》10
这里关键点是:add方法调用的时候,给add方法传递了一个参数i,到底传递的是什么?---传递的是值。
又如:
int i = 10;
int j = i; //i传递给j,实际上只是将i变量中保存的10传递给j了,j实际上是一块全新的内存空间。
再如:
User u = 0x1234;
User u2 = u; //u传递给u2,实际上是将0x1234这个值赋值给u2了,u和u2实际上是两个不同的局部变量,
//但是它们这两个变量指向堆内存中同一个java对象。
public class zhichuandi02 {
public static void main(String[] args) {
// 调用构造方法
User u=new User(20);
add(u);
System.out.println("main方法得到--》"+u);//21
}
public static void add( User u){
u.age++;
System.out.println("add方法得到--》"+u.age); //21
}
}
class User{
//实例变量
int age;
//构造方法
public User(int i ){
age =i;
}
}
总结:方法在调用的时候,涉及到参数传递问题时,java只遵循一种语法机制,将变量中保存的“值”传递过去,只不过有的时候这个值是一个字面值10,有时候这个值是另一个Java对象的内存地址。
对象和引用的概念复习
* 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象。
* 引用:是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。
* 所有访问实例相关的数据,都需要通过“引用.”的方式访问,因为只有通过引用才能找到对象。
* 只有一个空的引用,访问对象的实例相关的数据会出现空指针异常。
class Student{
Computer com; //com是一个引用【实例变量】
public static void doSome(){
Computer cc; //cc是一个引用【局部变量】
}
}
本章总结:
第四章 this关键字、static关键字、继承、方法的覆盖
1、this关键字
- 翻译为“这个”。
- this 是一个引用,this是一个变量,this变量中保存了内存地址,指向了自身。
- this 存储在 jvm 堆内存 java 对象的内部。
- 每个对象都有 this 。
- this 可以出现在“实例方法”中,this 指向当前正在执行的这个动作的对象。
- this 在多数情况下可以省略不写。
- this 不能使用在带有 static 的方法中。(因为带static的方法是通过类名的方式访问的,这个方法在执行过程不需要对象的参加,,不能用this)
- 当时用 c1 访问该对象的话,整个过程中的 this 就是c1.
例1:在这个顾客购物的例子里学习this关键字的使用,和什么时候不带static关键字:
public class Customer {
String name;
// 构造方法
public Customer(){
}
// 不带static关键字的方法
// 顾客购物的行为,是对象级别的行为。
// 由于每个对象在执行购物这个动作最终结果都不同,所以购物这个动作必须有“对象”的参与。
// 重点:没有static关键字的方法别成为实例方法。
// 重点:没有static关键字的变量被称为实例变量
// (实例变量在堆内存的对象内部存储,所以访问该数据的时候,必须先创建对象,通过引用的方式访问)。
// 实例方法怎么访问? --引用.方法名()
// 注意:当一个行为或动作执行过程中,需要对象参与,这个方法一样要定义为实例方法,不要带static关键字。
// (以后自己写代码的时候,这个方法需要对象,就不要带static)
// 所以前面:public void setAge(){};为啥不加static,因为改年龄改的是对象的年龄,它是实例方法。
public void shopping(){
// 由于name是一个实例变量,所以这个name访问的时候一定访问的是当前对象的name。
// 所以多数情况下,这个“this”是可以省略的。
System.out.println(name+"在购物 ");
// 完整写法:引用.变量
System.out.println(this.name +"在购物 ");
// 这里的this,在主方法里面,谁调用了就是谁。
}
public static void doSome(){
// 这个方法在执行过程不需要对象的参加,,不能用this
// 因为带static的方法是通过类名的方式访问的。
// 或者说,上下文没有“当前对象”,自然也不存在this。(this带变大额是党万岁正在执行这个动作的对象)
// System.out.println(name);报错
}
}
public class CustomerTest {
public static void main(String[] args) {
// 创建customer对象
Customer c1=new Customer();
c1.name="zhangsan";
c1.shopping();
// 这里注意shopping构造方法的this写法
// 再创建一个
Customer c2=new Customer();
c2.name="wangwu";
c2.shopping();
// 调用doSome方法(修饰符有static)
// 采用 类名.方法名,这个方法在执行过程不需要对象的参加
Costomer.doSome();
// 调用doOther
Costomer.doOther();
}
}
例2:
public class ThisTest {
int num=10;
// 带有static的方法
// jvm负责调用main方法,,jvm是怎么调用的?
// ThisTest.main(String[]){};
public static void main(String[] args) {
// System.out.println(num);//这样是不对的,为什么?
// 因为num是实例变量,(引用.的方式访问)
// 当前没有对象this
// 想访问这个num怎么办?--使用这个类,创建对象
ThisTest tt=new ThisTest();
System.out.println(tt.num);
}
}
例3:
public class ThisTest {
// 带有static的主方法
public static void main(String[] args) {
// 调用doSome方法:以下两个方法都可以
ThisTest.doSome();
doSome();
// 调用doOther方法-实例对象必须先创建对象,通过引用.的方式访问
// ThisText04.doOther();//编译错误
// 实例方法必须先创建对象,通过引用.的方式访问。
ThisTest dd=new ThisTest();
dd.doOther(10,20);
// 注:由于main方法中没有this,所以以下方法不能用:
// doSome();//编译错误
// this.doSome();//编译错误
}
// 带有static方法
public static void doSome(){};
// 实例方法
public void doOther(int i ,int j){
// 这里有this,表示当前对象。
int sum=i+j;
System.out.println(sum);
};
// 再来一个实例方法
// run不带static ,run是实例方法。调用run方法一定是有对象存在的。
// 一定是先创建了一个对象才能调用run方法。
public void run(){
this.doOther(1, 2);//调用当前对象的doOther方法。
// 为什么这里可直接用this?
// 在大括号的代码中,一定是存在当前对象的,是有this的。
}
}
总结:实例变量和实例方法在static的方法中不能直接用,或者利用this使用。因为实例变量和实例方法都需要对象存在。
解决办法:使用这个类创建一个对象,然后在使用引用.的方式调用。
public class ThisTest {
// 这里有一个实例变量
String name;
// 这里有一个实例方法(没有static)
public void doSome(){};public static void main(String[] args) {
// 这里没有this,下面调用name和doSome()都不可以。
// System.out.println(name);
// this.doSome();
//
// 正确做法:
ThisTest tt=new ThisTest();
System.out.println(tt.name);
tt.doSome();
};
}
例4:this什么时候不能省?-用来区别局部变量和实例变量时不能省略。
(b站p140)
public class User {
// 属性
private int id;
private String name;
// 构造函数
public void setId1(int a ){
id=a;
}
// setId的这个构造函数为了见名知意,可以这样写
public void setId2(int id){
id =id;
//注意:由于就近原则,等号左右的id都是形参的id。
};
// 所以可以这么写:this不能省
public void setId3(int id){
this.id =id;
// 等号右边的id是局部变量id(形参),
// 等号左边的this.id是实例变量id(前面private int id;中的id)
};
}
总结:this什么时候不能省略?
用来区别局部变量和实例变量时不能省略。
例5:
总结代码:
(p142-p144)
public class thisTextzongjie {
// 带有static的方法
public static void method1(){
// 调用doSome(用完整方式和省略方式)
doSome();
// this.doSome();
thisTextzongjie.doSome();
// 调用doOther(用完整方式和省略方式)
thisTextzongjie dd=new thisTextzongjie();
dd.doOther();
// 访问i(用完整方式和省略方式)
// i不带static,为实例变量
System.out.println(dd.i);
}
// 没有static的方法
public void method2(){
// 调用doSome(用完整方式和省略方式)
doSome();
// 调用doOther(用完整方式和省略方式)
this.doOther();
doOther();
// 访问i(用完整方式和省略方式)
System.out.println(this.i);
}
// 主方法
public static void main(String[] args) {
// 要求:
// 在这里编写程序,调用method1(用完整方式和省略方式)
thisTextzongjie.method1();//
method1();
// 在这里编写程序,调用method2(用完整方式和省略方式)
thisTextzongjie mm=new thisTextzongjie();
mm.method2();
}
// 没有static的变量
int i=10;
// 带有static的方法
public static void doSome(){
System.out.println("do some!");
}
// 没有static的方法
public void doOther(){
System.out.println("do other!");
}
}
//总结:
//带有static的方法需要使用“类名.”的方式访问和引用.的方式访问(尽量不用)。
//实例对象: 引用.的方式访问
// 实例与实例之间,用thisv
第五章
1、多态基础语法
2、多态在实际开发中的作用
3、final关键字
4、关于package和import