此文章是本人大一学习java时记的笔记,原视频在https://www.bilibili.com/video/BV1Rx411876f,配套服用更佳!
一.JAVA开发环境的搭建
1.常用的Dos命令
1.1 win+r打开Dos命令窗口
1.2什么是Dos命令
在最初的计算机中没有图形界面,也就是说通过Dos命令窗口可以完全完成文件的新建、编辑、保存、删除等一系列操作。
1.3 mkdir abc
创建一个目录,起名abc
1.4 在Dos窗口中怎么复制内容
左键选中要复制的内容,右键点击一次,内容就到了剪贴板了。
1.5切换盘符
直接输入盘符即可。
c:回车 就到了c盘,同理其他也一样。
1.6切换目录
使用cd命令来完成目录的切换。
cd+路径
路径可以是相对路径也可以是绝对路径。
cd…回到上级目录
cd \ 回到根目录
cd+.代表当前路径
1.7 cls清屏
1.8 dir查看当前目录下有啥东西
1.9 exit 退出Dos命令窗口
1.10 del删除一个或者多个文件
del 1.txt 就删除了他
del *.txt 就删除所有txt文件
t1.class
t1.glass
del *ass 这个命令会将上述两个文件都删除。
1.11 怎么查看本机的IP地址
在命令框输入ipconfig(可查询ip地址的配置信息)
ipconfig /all 可查看更详细信息
1.12 怎么查看两台计算机可以正常通信
ping IP地址
ping 域名
例如 ping www.baidu.com
后面加个-t 就一直ping,直到人操作终止。
一直ping的目的是查看网络是否稳定。
在一个DOS窗口中一个命令一直执行,想结束
用ctrl+c结束。
1.13 DOS命令窗口中,可以使用tab键自动补全。
1.14 DOS命令窗口中,使用上下箭头可以翻出历史记录。
1.15 电脑快捷键
win+d 显示桌面
win+l 锁屏
2.文本快捷键
ctrl+s | 保存 |
---|---|
ctrl+z | 撤销 |
ctrl+y | 重做 |
ctrl+a | 全选 |
fn+home | 光标回到行首 |
fn+end | 光标回到行尾 |
ctrl+fn+home | 光标回到文章开始 |
ctrl+fn+end | 光标回到文章末尾 |
shift+上方向键或下方向键 | 选中一行 |
鼠标双击 | 选中一个单词 |
ctrl+shift+右箭头或左箭头 | 选中一个单词 |
鼠标连击三次 | 选中一行 |
ctrl+f | 查找 |
3.java语言特性
3.1简单性
java中真正操作内存的是:JVM(java虚拟机)
所有java程序都是运行在java虚拟机当中的。
而java虚拟机执行过程中再去操作内存。
而c语言时可以直接通过指针操作内存的。
因此
java优点:简单,不容易导致内存泄漏
缺点:效率问题。
java语言底层是c++,JVM是用c++写好的的一个虚拟的电脑。
安装了JDK后,JVM就安装好了。
计算机重要部件
cpu:中央处理器,相当于人类的大脑,负责发送并执行指令。
cpu负责计算,但计算过程中有数据需要临时找个空间存储一下:就需要内存
内存
程序执行过程中临时数据存储空间。
断电之后数据就消失了。
硬盘
持久化设备。
主板
相当于人的躯干,是一个载体。
3.2java是堪称完全面向对象的
面向对象更容易让人理解,使复杂问题简单化。
3.3健壮性
java中有一种机制
自动垃圾回收机制(GC机制)
JVM负责调度GC机制,程序员不需要干涉。
3.4 JVM
jvm是java虚拟机,用c++写好的,java程序实际没有直接和操作系统打交道。
java程序写出来后是一样的,windows上的jvm和mac上的不同,然后就可将java程序翻译成Windows和mac分别能看懂的语言。
jvm屏蔽了操作系统之间的差异
jvm是安装jdk的时候自带的。
因此jdk也分Windows和mac
3.5可移植性/跨平台
java语言只要编写一次,可以做到到处运行。
jvm这种机制实现了跨平台。
优点:一次编写到处运行。
缺点:麻烦,运行java程序必须先有一个jvm。
3.6 JDK、JRE、JVM三者之间的关系
jdk:java开发工具箱
jre:java运行环境
jvm:java虚拟机
jvm不能独立安装,jdk包括jre,jre包括jvm。
安装jdk,jre自动安装,jvm也自动安装
安装jre,jvm也自动安装
假如一个电脑只需将程序跑起来,那就值安装jre就行,不需要jdk
3.7 java从编译到运行
程序员写的java代码无法被jvm识别。必须经过编译变成字节码,才能被jvm识别。
java代码变成字节码的过程叫 编译
java代码被称为源代码。
字节码可以到不同系统去使用,因为java是跨平台的。
放源代码的文件扩展名是 xxx.java
编译生成的字节码文件扩展名是:xxx.class
1个java文件可编译生成多个class文件。
字节码不是二进制文件
如果是的话,就不需要jvm什么事情了。
需要使用的两个命令
javac命令,负责编译
java命令,负责运行
小插曲
xxx.java经过编译后生成了A.class B.class C.class,那么我们称A是一个类,B是一个类,C是一个类。
4.java使用
4.1 java下载以及环境变量配置
javac -version命令可查看java版本
path环境变量作用
告诉Windows系统去哪里找这个命令文件。
4.2javac命令怎么用
格式: javac java源文件的路径。
路径可以是绝对或相对。
javac 然后把java文件拖进命令框也可以。
除了win+r进入DOS命令框以外,还可以在文件夹地址栏输入cmd,这样的好处是进入DOS命令框后,路径深入,更好找到想找的java文件
4.3 java命令
java+类名
使用时
先用cd命令找到.class文件所在路径,然后在java+类名
4.4 classpath环境变量
进行
java+类命令后
第一步:会启动JVM(java虚拟机)
第二步:jvm启动之后,jvm会自动启动类加载器classloader
作用:负责去硬盘找类对应的字节码文件。
第三步:找不到就报错。
找到了,类加载器会将该字节码文件装载到jvm中,启动解释器将字节码解释为二进制码,操作系统执行二进制码和硬件交互。
类加载器找的是当前路径下的类文件。
能不能给加载器一个路径,直接让他去别的地方找??
但需要classpath
classpath环境变量不属于Windows操作系统,是java特有的。
配置classpath 后,java命令只会去配置classpath的文件夹找,不会在当前路径找,所以不如不配。
目前不需要classpath,理解即可、
java后面直接加java源文件路径,可以直接运行,但是这样不会生成class文件,现在没必要这么使用
5.java注释
//单行
/* */多行
这种叫javadoc注释:这里的注释信息可以自动被javadoc.exe命令解析提取并生成到帮助文档中。
/**
*
*
*
*/
6.类体
1.在java中任何有效代码必须写到类体中,最外层必须是一个类的定义。
2.public表示公开,class表示定义一个类,test是一个类名
例 public class test{
}
7.方法
1.main方法
public static void main(String[] args){
}
也可以
public static void main(String args[]){
}
整个这一块被称为main方法(程序的入口)
main方法也可以叫做主方法。
注意:方法必须放在类体中,不得放到类体外。
任何一个程序都要有入口。
能再来一次main方法吗?
不能,会有语法错误。
main方法中,arge可以改名字,对于主方法来说,只有这个位置可以改,
java语句必须写在方法里。
100和“100”不一样
±*/也都和c语言一样。
2.class
一个java文件中
class A{
}
class B{
}
可以运行吗?
可以的。并且生成两个class文件。
结论一:一个java源文件中可以定义多个class
结论二:public的类不是必须的。
结论三:public的类必须和源文件名保持一致
结论四:public的类也只能有一个
class t1{
public static void main(String[] arge)
system.out.println(“t1”);
}
class t2{
public static void main(String[] arge)
system.out.println(“t2”);
}
class t3{
public static void main(String[] arge)
system.out.println(“t3”);
}
要想运行这些,java+类名时 类名用t1,t2,t3即可
(不过一般不这样,只是为了理解)
一般软件的入口只有一个。
3.public class
必须和java文件名相同。
二.标识符与关键字
1.标识符可以标识什么
类名,变量名,方法名,变量名等等
数字,字母,下划线。以及¥,标识符也可以是中文。
关键字不能做标识符
2.可以命名123.java吗
可以,在Windows操作系统中文件名叫做:123.java没问题。
只不过在123.java文件中无法定义public的类。
因为类名不能以数字开头。
3.规范
见名起意
驼峰
类名,接口特殊要求
类名接口首字母大写,后面每个单词首字母大写。
变量名,方法名
首字母小写,后面每个单词首字母大写。
所有常量名全部大写,单词单词之间采用下划线衔接
4.关键字
蓝色字体,小写,是关键字。
三.变量
1.字面量
和c一样
2.变量
变量名首字母小写,后面字母大写
与c语言不同,java变量必须初始化(成员变量例外)
3.变量分类
在方法体当中声明的变量,叫局部变量。
在方法体之外的叫成员变量。
类似于c语言全局变量和局部变量。
与c语言相同。
局部变量只在方法体内有效,方法体执行结束变量的内存就释放了。
四.数据类型
4.1整型
数据类型分为两类在java中
1.基本数据类型
整数型:byte,short,int,long
浮点型:float,double
布尔型:true,false
字符型:用单引号括起来
2.引用数据类型
String属于引用数据类型
引用数据类型后期面向对象的时候才会接触。
3.区别
float double 以及 int long这些占据的空间不同
4.占用字节数量
类型 | 占用字节数量 |
---|---|
byte | 1 |
short | 2 |
int | 4 |
long | 8 |
float | 4 |
double | 8 |
boolean | 1 |
char | 2 |
5.取值范围
byte是[-128~127],可以标识256个不同数字。
byte类型最大值是怎么算出来的???
btye是一个字节,8个比特位。
byte最大值为 01111111
因为二进制位最左边的是符号位,为0时为正数,1时为负数。
所以byte最大为01111111
则是256
需要记忆的取值范围
byte -128~127 可以标识256个不同数字
short -32768~32767 可以标识65536个不同数字
int -2147483648~214783647
char 0~65535 可以标识65536个不同数字
6.字符编码
规定了一系列的文字对应的二进制
最开始支持的文字是英文,英文对应的字符编码方式是:ASCII码
ASCII采用1byte进行存储,因为英文字母只有26个,1byte足以表示。
‘a’–>97
‘b’–>98
‘A’–>65
‘B’–>66
‘0’–>48(文字0)
‘1’–>49
中文编码方式:GB2312<GBK<GB18030 (简体中文)
繁体中文:big5
java为了支持全球所有文字,采用unicode编码。
具体的实现包括:UTF-8 UTF-16 UTF-32
7.转义字符
\t \n与c一样
输出时
System.out.println()这种是输出后换行
System.out.print()这种输出后不换行。
想在控制台输出一个\字符咋办
System.out.println('\ ') 不行
因为\会把 '转义
因此就
System.out.println(’ \ \ ')
这样做\会把\转化为普通的\,就输出了。
同理,想在控制台输出一个’也一样
想输出"test"
System.out.println(“\“test\””)
或者 内引号用中文引号。
\u是 表示后面的是一个字符的unicode编码
System.out.println(‘\ u4e2d’)
本身’'里只能放一个字符,但\u会变成unicode编码,4e2d输出后是中字。
8.进制
十进制 10
八进制 010
十六进制 0x10
二进制 0b10
9.整数型被默认当做int处理
想被当做long处理,则在数字后面写L。
10.自动类型转换
long i=200;
200虽然被当做int,但是可以自动转换为long(没超过范围就可以)
long i=2147483645
编译器会报错吗???
会,因为java中会字面量被当做int处理,2147483645就是int,然后超出范围了
byte<short(char)<int<long<float<double
11.强制类型转换
long x=100L
int y=(int)x
才能编译通过,但会损失精度
byte b=300可以编译通过吗???
不行,300的int要转换为byte,必须强制类型转换
int类型的300 是 00000000 00000000 00000001 00101100
byte自动砍掉前三字节,00101100就是44
12.整数能否直接赋值给char
char x=97
输出结果为’a’
将整数赋值给char,会自动转化为char型。
13.二进制补码
1.计算机在任何情况下都只能识别二进制
2.计算机在底层存储数据时,一律存储的是二进制的补码形式。
3.什么是补码
二进制包括:原码,反码,补码
4.对于一个正数来说:原码,补码,反码是同一个,完全相同。
对一个负数来说:
byte i=-1
原码 10000001
反码 11111110(符号位不变,其他位取反)
补码 11111111(反码+1)
byte b=(byte)150
150转换为二进制 00000000 00000000 00000000 10010110
byte后 剩下 10010110
(计算机中存储的永远都是二进制补码形式)
所以 反码 =补码-1 :10010101
原码:11101010
所以b=-106
14. char+byte
char c1=‘a’
byte b=1
输出c1+b为一个int型的98
结论:byte char short做混合运算的时候,各自先转换成int再做运算。
short s=c1+b(报错) 与 short k=98(正常)
为什么???
第二种正常说明98并没有超出范围,第一种是加法运算,编译器编译时并不知道他的结果超出范围了没,只有运行的时候才会出结果,所以需要强制类型转换。
同理
int a=1
short x=a;
(错误)
与上面同理,编译过程中,计算机只判断a是int型,int型赋给short就得需要转换,他不会知道a很小。
15.多种类型运算
long a=10L
char c=‘a’
short s=‘100’
int i=30
求和后是long型
结论:多种数据类型做混合运算时,最终的结果类型是“最大容量”对应的类型。
但char+short+byte混合除外,因为这个会各自转换为int再运算。
4.2浮点型
float 4字节
double 8字节
float是单精度,double双精度
double更精确
long 8字节 float 4字节 哪个容量大??
注意:任意一个浮点型都比整数型空间大。
java中规定,任何一个浮点型数据默认被当做double来处理如果想让被当做float类型出行,后面加F或f,或者用强制类型转换,但可能会损失精度
4.3 boolean型
在java中只有true和false ,和c语言不同,不能用0和1表示。
一般用在逻辑判断中。
int a=10
int b=20
boolean flag=a<b
输出flag就是true
五.运算符
&有一边为false,即为false。
|有一边为true,即为true。
1.短路
&和&&结果相同
但&&会有短路效果,&&左面表达式是false,决定整个式子是false了,右边就不会进行。
同理||也一样。
2. i=i+1和i+=1真的一样吗???
byte x=100;
x=x+1 [会报错,1是int类型,x+1也是int类型,直接赋值给byte,会报错]
x+=1 [不会报错,扩展赋值运算符,不会改变运算结果类型。]
x+=1等同于:x=(byte)(x+1)
3.三目运算符
跟c一样
4.运算符(字符串拼接)
当+运算符两边的任意一边是字符串类型,那么这个+会进行字符串拼接操作。
字符串拼接完之后的结果还是一个字符串
加法遵循自左向右。
例子
在控制台输出 100+200=300
int a=100,b=200
System.out.println(a+“+”+b+“=”+c)
字符串拼接易错题
'5'+2 //等于55
"5"+2 //等于52
5.如果定义字符串型变量
String name=“zhang”
六.接收用户键盘输入(先不用理解)+退出JVM
java.util.Scanner s=new java.util.Scanner(System.in);
int i=s.nextInt(); [输入整型]
String str=s.next(); [输入字符串]
double score=s.nextDouble() [输入小数]
System.exit(0); 退出jvm
七.if 三目 Switch
1.Switch
Switch(值)
值支持int类型以及String类型。
byte short char也可以使用在Switch里。因为可自动类型转换
但是long 型的不行
case 1:
....... ;
break;
case 2 :
.......;
break;
想合并就
case1: case2:
........;
break;
八.转向语句
break的一种特殊用法
a:for(){
b:for(){
i f(){
break a;
}
}
}
这样可以选择终止哪个循环。
九.方法
跟c语言函数类似。
语法机制
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
注意: []里的不是必须的。
修饰符列表目前写成public static ,后续就知道怎么写了。
1.返回值类型
所有基本数据类型和引用数据类型。
2.返回值类型不是void,就必须有return
3.类名省略
当a方法调用b方法时,a和b方法都在同一个类中,“类名”可以省略。如果不在同一个类中不能省略。
意思是a,b在同一个类时,引用直接 方法名()就行。
不在同一类,引用得 类名.方法名()
4.return 用来终止离他最近的一个方法。
5.缺少返回语句
public static int m(){
boolean flag =true;
if(flag){
return 1;
}
}
上述程序会报错
编译器不会知道flag是true型,他只知道如果flag是false,则没有返回值,而int方法必须有返回值、
6.JVM(java虚拟机)内存结构
JVM中主要的三块内存空间:
栈、堆、方法区
栈:在方法被调用时候,该方法需要的内存空间在栈中分配。
堆:以后讲。
方法区:类加载器classloader,将硬盘上的XXX.class字节码文件装载到JVM的时候,会将字节码文件存放到方法区当中。也就是说方法区存储的是代码片段。
因为类需要加载,所以方法区当中最先有数据。
7.方法执行过程中内存变化
1.方法区最先有数据:方法区中放代码片段,存放class字节码。
2.方法只有在调用的时候才会在栈中分配空间,并且调用时就是压栈。
3.方法执行结束后,该方法所需要的空间就会释放,此时发生弹栈动作。
4.栈中存储什么? 方法执行过程中需要的内存,以及栈中会存储方法的局部变量。
类加载器将字节码文件放到方法区里,然后开始执行,最初执行main方法,main方法的栈帧先在栈区有空间,然后调用m1,m1也在栈区里。最后m3、m2、m1、main依次顺序弹栈
8.方法重载
[想求int的和,小数的和,long型的和需要创三个方法]
如果不使用方法重载,有什么缺点???
1.代码不美观
2.程序员记忆方法名很累
方法重载
功能相似的方法给一样的方法名。
比如int求和,long求和,double求和。
都
public static int sum(int a,int b)
public static long sum(long a,long b)
public static double sum(double a,double b)
调用的时候都用sum就行,编译器会根据你给参数的数据类型判断去哪里执行。
重载
{
在一个类中
方法名相同
参数列表不同
1.个数不同
- 类型不同
- 顺序不同
}
9.函数递归
跟c语言递归一个道理
递归可能会导致栈空间不足。所以必须有结束条件。
但即使有结束条件,也可能会栈空间不足。(有可能递归太深)
可以用java-X命令查询,如何更改栈空间之类的操作。
n的阶乘
public class test{
public static void main(String[] args){
int a=sum(4);
s.p(a);
}
public static int sum(int n){
if(n==1){
return 1;
}
return n*sum(n-1);
}
}
十.面向对象
1.面向对象和面向过程区别
面向过程:c语言
注重的是实现这个功能的步骤
面向过程也注重实现功能的因果关系。
面向过程中没有对象的概念,只是实现这个功能的步骤。
缺点
面向过程主要是一步一步的因果关系,其中A步骤因果关系到B步骤,A和B联合起来形成一个子模块,子模块和子模块之间又因为因果关系结合在一起,假设其中一个因果关系出现问题(错误),此时整个系统的运转都会出现问题。(代码和代码粘合度高,扩展力差)
优点
小型项目,直接干活,编写因果关系,从而实现功能。
面向对象
采用面向对象的方式进行开发,更符合人类的思维方式。
面向对象就是将现实世界分割成不同的单元,然后每一个单元都实现成对象,然后驱动一下,让各个对象之间写作起来形成一个系统
例子
对象”张三“
对象“香烟”
对象“打火机”
然后将上面对象组合在一起,就可以模拟一个人的抽烟场景。
其中“张三”还可以换成“李四”。
扩展力强
2. OOA OOD OOP
OOA: 面向对象分析
OOD:面向对象设计
OOP:面向对象编程
上述为实现一个软件的过程。
3.面向对象三大特征(了解,后面讲)
封装
继承
多态
任何一个面向对象的编程语言都包括这三个特征。
4.类和对象的概念
什么是类?
类实际上在现实世界中是不存在的,是一个抽象的概念,是一个模板。是我们人类大脑进行思考,总结,抽象的一个结果。
什么是对象?
对象是实际存在的个体。
例如
赵露思是一个对象
鹿晗是一个对象
刘德华是一个对象
这三个对象都属于“明星”这个类。
在java中,要想得到“对象”,必须先定义“类”,“对象”是通过“类”
这个模板创造出来的、
类就是一个模板:类中描述的是所有对象的共同特征信息,对象是通过类创建出的个体。
类=属性+方法
属性来源于状态,方法来源于动作。
public class 明星类{
//属性–>状态,多见于名词。
名字属性:
身高属性:
//方法–>动作,多见于动词。
打篮球方法(){}
study方法(){}
}
5.java程序员是一个转换的桥梁
将现实生活中的一些事物转换。
具备 观察+抽象能力,观察现实世界中对象1和对象2的共同特征,然后在java程序中使用“类”来描述这些共同特征,然后通过“类”实例化“对象”,让对象之间互相协作起来形成系统,模拟现实世界。
6.类的定义
6.1 怎么定义一个类?
[修饰符列表] class 类名{
//类体=属性+方法
//属性在代码上以“变量”的形式存在(描述状态)
//方法描述动作/行为
}
属性其实就是成员变量
6.2对象的创建
public class XueSheng{
int xuehao;
int nianling;
char xingbie;
}
之后在其他地方
new XueSheng();就行。
但是你创建了想使用的话,必须接收一下他。
接收东西,比如 int b=10;
变量类型+变量名=
因此,创建对象是: XueSheng s1=new XueSheng ();
类就是引用数据类型
6.3 编译过程
按理来说,需要先编译那个类的文件,再编译使用类去弄出来的对象的文件。
但是
可以直接编译对象那个文件,这样类文件会自动编译。
6.4创建对象对应的jvm内存结构
之前说,变量必须声明,赋值后才能使用。
但成员变量,没有赋值时,系统默认赋值
类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
boolean | false |
char | \u0000 |
引用数据类型 | null |
实例变量
对象又被称为实例。
实例变量实际上就是:对象级别的变量。
public class 明星类{
double height;
}
身高这个属性所有明星对象都有,但是每一个对象都有“自己的身高值”。假设创建10个明星对象,height变量应该有10份。
所以这种变量被称为对象级别的变量,属于实例变量。
因此,不能通过类名直接访问实例变量,必须创键对象。
对象和引用
对象是通过new出来的,在堆内存中存储。
引用是:但凡是变量,并且该变量中保存了内存地址指向了堆内存当中的对象的。
怎么访问实例变量
语法:引用.实例变量名
实例变量都是默认值,如何修改
直接通过=赋值进行修改。
6.5 内存图
内存图上不要体现出代码,主要体现数据
画内存图是对java运行机制的一种理解,有助于以后复杂程序出错的调试。
画图时,应有先后顺序。
6.6 引用一定是局部变量吗?
不一定
new的某个对象里面也可以有一个引用指向其他对象。
就类似c语言结构体里面还有一个结构体的感觉。
通过引用的目的是访问对象里面的数据。
6.7 属性是引用类型怎么访问。
一个例子
如何从test类一直访问到i的值
public class test{
A o1;
public static void main(String[] arge) {
D d =new D();
C c =new C();
B b =new B();
A a =new A();
test t =new test();
c.o4=d;
b.o3=c;
a.o2=b;
t.o1=a;
System.out.println(t.o1.o2.o3.o4.i);
}
}
class A{
B o2;
}
class B{
C o3;
}
class C{
D o4;
}
class D{
int i=100;
}
6.8空指针异常(NullPointerException)
public class NullPointertest{
public static void(String[] args){
customer c=new customer();
System.out.println(c.id);//0
//若c为null会怎样?
c=null;
System.out.println(c.id);//NullPointerException
}
}
java中的垃圾回收器 GC
在java语言中主要针对的是堆内存,在一个java对象没有任何引用指向该对象的时候,GC会考虑将该垃圾数据释放回收掉。
6.7中的代码
如果
c.o4=d;
b.o3=c;
a.o2=b;
t.o1=a;
这一段不写,也会出现空指针异常。
因为o1 o2 o3都是空的,无法点点点,必须把new来的对象赋给他们。
空指针异常的前提条件
“空引用”访问实例相关【对象相关】的数据时,都会出现空指针异常
6.9方法调用时参数的传递问题
参数传递只是将值复制一份传递下去。
跟c语言一样,变量有作用域,在某个方法里i++了,但出了这个方法i还是原来的值。
但是! 参数如果是对象,传递的是地址,比如传递一个p,p点什么什么不管在哪个方法里都是一样的,因为传递前后地址一样。(跟c语言指针差不多)
7.构造方法
7.1什么是构造方法,有什么用?
构造方法是一个比较特殊的方法,通过构造方法可以完成对象的创建,以及实例变量的初始化。换句话说:构造方法是用来创建对象,并且同时给对象的属性赋值。(注意:实例变量没有手动赋值的时候,系统会赋默认值。)
7.2 当一个类没有提供构造方法时,系统会默认提供一个无参数的构造方法(这个构造方法被称为缺省构造器)。但是当一个类中提供了方法时,系统就不会再提供那一个无参数的构造方法了,这时你想调用无参的这个方法,就会报错
7.3构造方法如何调用?
使用new运算符来调用构造方法
new+方法名+(实参)
7.4 构造方法的语法结构是?
[修饰符列表] 构造方法名 (形式参数列表){
构造方法体;
通常在构造方法体当中给属性赋值,完成属性的初始化。
}
修饰符列表目前统一写 public,千万别写public static。
构造方法名和类名必须一致。
构造方法不需要指定返回值类型,也不能写void。
普通方法语法结构
[修饰符列表] 返回值类型 方法名 (形式参数列表){
方法体;
}
构造方法支持重载,因为构造方法名必须跟类名相同,所以当参数不同,就重载了。
7.5 实例变量初始化啥时候?
创键了对象后。
十一.封装
1.面向对象的三大特征
封装
继承
多态
2.面向对象的首要特征:封装
2.1 什么是封装?
现实生活中例如手机,电视机。外部有一个坚硬的壳,保护内部部件安全。
对于使用者来着,看不见内部复杂结果,我们也不需要看见,只需要操作外部的几个按钮就行。
2.2 封装有什么用?
1.保证内部结构安全
2.屏蔽复杂,暴露简单
在代码级别上,封装有什么用?
一个类体当中的数据,假设封装之后,对于代码的调用人员来说,不需要关心代码的复杂实现,只需要通过一个简单的入口就可以访问了。
另外,类体中安全级别较高的数据封装起来,外部人员不能随意访问,来保证数据的安全性。
2.3不封装有什么问题
例如person对象里的属性age,如果不封装,年龄可在外部任意更改,哪怕给年龄负数,也不会报错,不符合业务要求。
2.4尝试封装一下
不再对外暴露复杂的数据,封装起来。
对外只提供简单的操作入口。
优点:第一数据安全了,第二调用者也方便了。
2.5怎么进行封装?
第一步:属性私有化(使用private关键字进行修饰)私有的可以在本类中访问
第二步:对外提供简单的操作入口。(set+get);
private
public class Person{
//被这个关键词修饰以后,该数据只能在本类中访问。
//出了这个类,age属性就无法访问了,私有的。
private int age;
}
之后new对象后,想输入和修改这个对象的age值,编译会报错说age在Person中被private控制。
age彻底在外部不能访问了,但是这有点太安全了。age不能访问,这个程序就意义不大了。
因此还需要对外提供简单的入口,外部程序只能通过调用以下的代码来完成访问。
思考:你应该对外提供几个访问入口。
思考:这些操作入口是否应该是方法呢。
写一个方法专门来完成读(get)
写一个方法专门来完成写(set)
中间引入一个实例方法
带有static的方法
不带static的方法
(后面会讲为什么)
分别怎么调用?
带static通过类名.的方式访问
不带static的被称为实例方法
对象被称为实例。
实例相关的都需要先new对象,通过引用.的方式去访问。比如实例方法。
实例方法跟构造方法一样,也会出现空指针异常
空指针异常导致的根本原因是?
空引用访问“实例相关的数据”,会出现空指针异常。
实例相关的包括:实例变量,实例方法。
接着2.5继续
get和set应该带有static还是不该?
不应该,改年龄和读年龄都是操作一个对象的年龄。
封装第二步(第一步是private):对外提供公开的set方法和get方法作为操作入口
public class Person{
//被这个关键词修饰以后,该数据只能在本类中访问。
//出了这个类,age属性就无法访问了,私有的。
private int age;
public int getAge(){
return age;
}
public void setAge(int nianling){
age=nianling;
}
}
java开发规范中有要求,set方法和get方法的格式
get
public 返回值类型 get+属性名首字母大写(无参){
return xxx;
}
set
public void set+属性名首字母大写(有一个参数){
xxx=参数;
}
十二 static
1.static
static翻译为“静态的”
所有static关键字修饰的都是类相关的,类级别的。
所有static修饰的,都是采用类名.的方式访问
static修饰的方法:静态方法。
变量分为局部变量和成员变量
成员变量又分为静态变量和实例变量
class vartest{
//实例的都是和对象相关,访问时用引用.访问。需要先new,可能出现空指针异常
int i; //实例变量
public void m2(){
//实例方法
}
//以下静态的,都是类相关的,访问采用类名.的方式。不需要new,没有空指针异常的发生。
static int k; //静态变量
public static void m1(){
//静态方法
}
}
2.什么时候用静态的,什么时候用实例的。
一个对象一份的是实例变量,所有对象一份的是静态变量。
中国人的例子
public class staticTest{
public static void main(String[] arge){
}
class Chinese{
String idcard;//idcard每个人都不一样,所以不加static,是实例变量。
String name;//name也不一样
String country;//对于中国人这个类来说,country都一样,先假设他是实例,画下面内存图,看有什么问题。
}
}
由图能看出,country每个人都一样,但因为是实例变量,所以每次都new出country,浪费了不必要的空间。
因此给country加static
public class staticTest{
public static void main(String[] arge){
}
class Chinese{
String idcard;//idcard每个人都不一样,所以不加static,是实例变量。
String name;//name也不一样
static String country;//对于中国人这个类来说,country都一样.
}
}
static String country 是成员变量,会给默认值,但他不像实例变量,实例变量是在new对象时给默认值
静态变量在类加载时初始化,不需要new对象,静态变量存储在方法区。
在方法区内加载chinese类时,发现chinese类中有一个静态变量,此时会给该静态变量初始化。
此时,要访问country,静态变量,所以用 chinese.country访问。
如果你想 chinese.idcard 则会报错 无法从静态上下文中引用非静态变量idcard 意思是chinese是class,是静态的,idcard是实例变量,是非静态的,无法这么引用。
栈—局部变量 堆—实例变量(对象级别) 方法区—静态变量(类级别)
3.空引用访问静态变量
实例一定需要引用.访问
静态的建议使用类名.访问(引用.也行)(不建议)。
同时,若用空引用访问静态变量,
c1=null c1.country
不会出现空指针异常,因为静态变量不需要对象的存在。
因此,只有在“空引用”访问“实例”相关的,才会出现空指针异常。
4.关于实例方法的调用
静态方法 使用类名.,也可以引用.,但不建议
实例方法 new对象,用引用.来访问。
什么时候定义为实例方法?什么时候定义为静态方法?
方法一般都是描述了一个行为,如果说该行为必须由对象去触发,就定义为实例方法
比如之前的set和get方法(年龄),他是为了让外界查找年龄或者更改年龄,而年龄是每个对象不一样,所以要定义为实例方法。
如果某个方法体执行过程中访问了实例变量,那这个方法必须定义为实例方法
开发中,大部分情况下,如果是工具类的话,工具类中的方法一般都是静态的。
工具类就是为了方便开发的一些类。直接类名.去访问,比较方便。
//例子
//打印名字
class User{
private int id;
private String name;
public void printName1(){
System.out.println(name);
}
public static void printName2(){
System.out.println(name); //name是一个实例变量,在方法体内访问实例变量,那方法必须是实例方法,不能是static
}
}
5.静态代码块
5.1使用static可以定义静态代码块
5.2什么是静态代码块?
static{
java语句
java语句
}
5.3static静态代码块什么时候执行呢?
类加载时执行,并且只执行一次。
static{
System.out.println(A);
}
public static void main(){
System.out.println(hello);
}
static{
System.out.println(B);
}
输出是 A B hello
因为静态代码块是类加载时执行的,main方法时在栈里执行,先类加载完,才会让main方法压栈,才执行main里的输出。
5.4静态代码块有什么用?
为java程序员准备的一个特殊时机,时间点。
5.5 先后顺序
静态代码块和静态变量都在类加载的时候执行,时间相同,只能看代码先后顺序判断谁先谁后。
静态代码块不能访问实例变量,因为实例变量是在new对象时才有的。
6.实例语句块
6.1实力语句块语法
直接一个{}
6.2实例语句块不是在类加载时执行
6.3实例语句块在构造方法执行之前执行。
叫做对象构建时机。
6.4实例语句块有什么用
比如你有很多的构造方法,但他们的前几句代码都一样,你就可以写到实例代码块里,不管调哪个构造方法,都会先进行实例语句块。
十三.this
1.this是一个关键字,全部小写、
2.this是什么?
一个对象一个this。
this是一个变量,是一个引用。this保存的当前对象的内存地址,指向自身。
所以this代表的就是当前对象,this存储在堆内存当中对象的内部。
1.this的应用
this只能使用在实例方法中。谁调用这个实例方法,this就是谁。所以this代表的是:当前对象。
public static void main(String[] arge){
user s1=new user("张三");
user s2=new user("李四");
}
class user{
String name;
public user{
}
public user(String s){
name=s;
}
public voud shopping{
System.out.println(this.name+"正在购物!")
//为什么不能写c1.name?
//c1是在main方法中定义的,是局部变量,去了别的方法不能用,但想调用name这种实例变量,必须“引用.”,所以产生this。
}
}
同时,更好的理解什么时候定义实例方法,什么时候定义静态方法。
如果方法体里有实例变量,想访问它,就是this.name,必须是实例方法里才能出现this。
只是一般this省略了
2.this什么时候不能省略?
class Student{
private int no;
private String name;
public Student(){
}
public Student(int no,String name){
//int no,String name 为什么不用int i?因为代码无可读性。
this.no=no;
this.name=name;
//这个时候this不能省略,如果省略就是no=no,就近原则。将没有意义。
}
//同理 get和set方法里也不能省略。
}
3.通过this()在一个构造方法里调用另一个。
class Date{
private int year;
private int month;
private int day;
public Date(){
/*
代码重复
this.year =1970;
this.month=1;
this.day=1;
*/
this(1970,1,1);
}
public Date(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
}
this()使用一个构造方法去调用当前类的另一个构造方法,是代码简洁
特别注意
对this的调用必须是构造器中的第一个语句!!!!!!
22/12.8
十四.继承extends
1.什么是继承?
使用继承解决代码臃肿。
一个类中的全部代码(父类)在另一个类(子类)也有。
可继承父类所有代码,除了构造方法以外
父类 class one{}
比如子类
class two{}
只需在子类 class two extends one{}即可
2.作用
基本作用:代码的复用。
主要作用:有了继承,才有了后期的方法覆盖和多态机制、
3.继承的相关特性
B类继承A类,则称A类为超类(superclass),父类,基类。
B类则称为子类(subclass),派生类,扩展类
java中的继承只支持单继承,c++支持多继承
不过可以好几个类同时继承一个类。
如果想继承好几个类
class a{
}
class b extends a{
}
class c extends b{
}
这样c就同时继承了a和b
直接继承b,间接继承a。
3.除构造方法外,其他都能继承。 但是私有的属性无法在子类中直接访问。
4.java中,所有的类默认继承object类。
5.继承缺点:一改父类,子类受牵连。
4.什么时候用继承
从语文上理解,cat是animal,所以cat能继承animal
5.object类中的toString方法
每个类都会自动继承object类。
toString是实例方法。
需要先new对象。
class project{
project pro=new project();
System.out.println(pro.toString);
//project@5305068a
//@前面是类名,后面的可等同看做对象在堆内存当中的内存地址。
//实际上的内存地址经过“哈希算法”得出的十六进制结果。
//如果直接输出引用呢
System.out.println(pro);
//project@5305068a
//println方法会自动调用pro的toString()方法。
}
因为println会自动调用引用的toString()方法,所以可以利用方法覆盖把toString改成自己想要的内容,然后调用时println(引用)就行,很方便、
十五.方法的覆盖和多态
1.方法覆盖override
方法覆盖,方法重写,override overwrite
1.1什么时候方法重载overload(回顾)
在一个类中,功能相似的话,建议将名字定义的一样,代码美观。
什么条件满足后能构成方法重载?????
1.在同一个类中
2.方法名相同
3.参数列表不同(个数.顺序.类型)
1.2方法覆盖例子
public static void main(String[] arge){
cat s1=new cat();
dog s2=new dog();
s1.move();
s2.move();
}
class Animals{
public void move(){
System.out.println("动物在行动");
}
}
class cat extends Animals{
public void move(){
System.out.println("猫在走猫步");
}
}
class dog extends Animals{
public void move(){
System.out.println("狗在跑步");
}
}
继承后的某些方法不能满足业务需求,直接把方法重写一次,然后改掉里面想更改的就行。
1.3方法覆盖条件
1.两个类必须有继承关系
2.重写后的方法和原方法一切都相同(除了想更改的)。
3.访问权限不能更低,可以更高。 【先记住】 修饰符列表 protected(受保护的)比public低。
4.重写之后的方法不能比之前的方法抛出更多的异常,可以更少(这个先记住)。
1.4注意事项
1.方法覆盖只是针对方法,和属性无关
2.私有方法无法覆盖。
3.构造方法不能被继承,所以构造方法也不能被覆盖
4.只是针对实例方法覆盖,静态方法覆盖没有意义
2.多态的基础语法
了解多态之前,先了解
1.向上转型
子------>父(自动类型转换)
2.向下转型
父------>子(强制类型转换,需要加强制类型转换符)
无论向上还是向下,两者之间必须有继承关系
1.1向上转型
例如之前写过的一些例子,有父类animal,子类cat和bird。
animal s1=new cat();
这样也是允许的。
cat is a animal。
父类型的引用允许指向子类型的对象。
那么
s1.move();//输出什么呢? 猫走猫步
为什么???
什么是多态?
多种形态,多种状态。
分析 s1.move();
java程序分为编译阶段和运行阶段。
先来分析编译阶段:
对于编译器来说,编译器只知道a2的类型是animal,所以编译器在检查语法的时候,会去animal.class字节码文件中找move()方法。找到之后绑定上,静态绑定成功(编译阶段静态绑定)
运行阶段:
实际上在堆内存创建的java对象是cat对象,所以move的时候,真正参与move的对象是一只猫,所以运行阶段会动态执行cat对象的move()方法。这个过程属于运行阶段绑定。(运行阶段属于动态绑定。)
多态表示多种形态,编译的时候一种形态,运行的时候一种形态
//假如cat类里还有抓老鼠catchMouse这个方法
animal s1=new cat();
s1.catchMouse();//可以运行吗???
不行!!
因为分析要先分析编译阶段,编译时编译器认为s1是个animal,去animal字节码文件里找,找不到catchMouse方法,就报错了。
1.2向下转型
什么时候要向下转型????
父类中没有的,子类中特有的(猫抓老鼠)
需要访问子类中特有的方法时,必须向下转型
cat x=(cat)s1;//s1是上面代码块那个s1
x.catchMouse;//就可正常运行了
//s1是animal,将animal强制转化为cat,就可以抓老鼠了。
向下转型有风险吗
animal s2=new bird();
cat x=cat(s2);
x.catchMouse;
这段代码
先分析编译阶段:
没有任何问题,编译器认为s2是动物,然后转成猫,没问题。
运行阶段:
一个鸟怎么能转换成猫呢,猫和鸟没有继承关系。
这个异常十分重要::: java.lang.ClassCastException
1.3怎么避免ClassCastException的发生
运算符instanceof
第一:instanceof可以在运行阶段动态判断引用指向对象的类型。
第二:instanceof的语法
(引用 instanceof 类型)
第三:instanceof运算符的运算结果是true/false
第四:c是一个引用,c变量保存了内存地址指向了堆中的对象。
假设(c instanceof cat)为true,则c引用指向的堆内存中的java对象是cat
反之,则不是cat。
因此,向下转型前需要判断
if(s2 instanceof cat){
cat x=(cat)s2;
x.catchMouse;
}
在向下转型前判断s2是cat才继续进行,确保不会造成从鸟转换成猫的悲剧。
任何时候向下转型时,必须使用instanceof,好习惯
1.4 为什么要用instanceof,自己判断是什么猫还是鸟不就行了吗
public void test(animal a){
cat c=(cat)a;
c.catchMouse();
}
//这个test方法,被传过来的不确定是猫还是鸟,所以像上面这么写就容易发生异常,所以需要用instanceof。
3.多态在开发中的作用
比如主人喂养宠物,今天主人可能喜欢狗,喂的是狗,明天主人喜欢猫了,如果不使用多态,那就得再写一次喂狗的方法,软件的扩展性很差。
使用多态,能提高扩展性。编译的时候编译器发现Pet是pet类,会去pet中找eat方法,结果找到了,编译通过
运行的时候,底层实际的对象是什么,就自动调用到该实际对象对应的eat(
方法上,这就是多态的作用。
面向父类型编程,面向更加抽象进行编程,不建议面向具体编程。
一些多态练习的例子: 乐手弹奏不同的乐器,主人喂养不同的宠物、
4.静态方法没有方法覆盖
假设没有多态机制,只有方法覆盖机制,你觉得有意义吗?
没有多态机制的话,方法覆盖可有可无。
没有多态机制的话,方法覆盖也可以没有,如果父类的方法无法满足子类业务需求的时候,子类完全可以定义一个新的方法。
Animal a=new Cat();
a.dosome();//dosome为静态方法
//这样,虽然用引用.调用,但是静态方法,所以还是animal. ,起不到多态的作用,方法覆盖也没有意义。
5.私有方法不能覆盖
私有不能覆盖,静态不谈覆盖。
6.方法覆盖时返回值类型问题
6.1 基本数据类型
方法覆盖前后的方法数据类型必须一致,该是int就是int
6.2 引用数据类型
父类时是ainimal,子类时是cat可以,java中允许。
父类时是animal 子类时是object,不行,java中不允许。
十六.super
1.super是一个关键字,全部小写。
2.super和this对比着study。
this:
this能出现在实例方法中和构造方法中。
this语法是 this.和this()
this不能用在静态方法中。
this大部分情况下可以省略、
this在区分局部变量和实例变量时候不能省略。
this()只能出现在构造方法第一行,通过当前的构造方法去调用“本类”中的其他构造方法,目的是:代码复用。
super:
可以出现在实例方法和构造方法中。
super语法是 super.和super()
不能用在静态方法中。
大部分情况下可以省略、
super什么时候不能省略呢?
super()只能出现在构造方法第一行,通过当前的构造方法去调用父类中的其他构造方法,目的是:创建子类对象的时候,先初始化父类型特征。
1.super()
表示通过子类的构造方法调用父类的构造方法。
模拟现实世界中的这种场景:要想有儿子,先有父亲。
2.重要结论
当一个构造方法第一行:
既没有this()也没有super(),会默认有一个super()
表示通过当前子类的构造方法调用父类的无参数构造方法
所以必须保证父类的无参数构造方法存在(不然就报错了)。
this()和super()不能共存!
class A{
public A(){
System.out.println("1");
}
}
class B extends A{
public B(){
System.out.println("2");
}
public B(String name){
System.out.println("3");
}
}
class C extends B{
public C(){
this("zhangsan");
System.out.println("4");
}
public C(String name){
this(name,20);
System.out.println("5");
}
public C(String name,id){
super(name);
System.out.println("6");
}
}
如果new一个c对象,输出结果是什么
13654
3.super(实参)是干啥的?
初始化当前对象的父类型特征,并不是创建新对象。[当你创建一个新对象,想初始化父类型特征,如果你在子类中用this.初始化,没用的,因为this.只能在本类(也就是父类)中用,因为引入super()来初始化父类型特征]
4.super关键字代表什么?
super关键字代表的就是“当前对象”的那部分父类型特征。
例如:
我继承了我父亲的一部分特征:
例如:眼睛、皮肤等。
super代表的就是“眼睛、皮肤等”
“眼睛、皮肤等”虽然是继承了父亲的,但这部分是在我身上呢。
5.super.什么时候不能省略
父中有,子中又有,如果想在子中访问“父的特征”,super.不能省略。
java中
this.name :当前对象的name属性。
super.name:当前对象的父类型特征的name属性。
6.super和this
直接输出this,会自动引用this的toString方法
直接输出super,会报错
结论
super不是引用,super也不保存内存地址,super也不指向任何对象。
super只是代表当前对象内部的那一块父类型的特征。
标签:java,int,某站,class,2000,实例,Java,方法,public From: https://blog.csdn.net/qq_73210658/article/details/142496914