一:java的写法
1,能自己搭建java环境
2、能够编写hello Word程序
3、掌握环境变量path的原理,以及如何配置
4、掌握环境变量classpath的原理以及如何配置
* class path是给classloader类加载指路的
* classpath=自己写的java代码文件的路径
5、java的注释
6、public class和 class区别
* 一个java源文件中当中可以定义多个class
* 一个java原文件中public 的class不是必须的
* 一个class是会定义生成一个xxx.class字节码的文件
* 一个java源文件中定义公开的类的话,public的class只能有一个,而且该类的名称必须和java源文件名一致
* 每一个class都可以编写main方法,都可以设置程序的入口
* 想执行那个程序,就执行相应的方法
注意:当命令窗口执行java hello 那么要求hello.class必须有主方法
二: java的语言基础
1、java的方法的名规则习惯
1、标识符:
标识符可以标识什么元素
* 类名
* 方法名
* 变量名
* 接口名
* 常量名
高亮显示为黑色的为标识符
命令规则:
* 只能由数字,字母,下划线,美元符号,
* 且不能有数字开头
* 区分大小写
* 不能是关键字
命名规范:
* 最好知名之意
* 遵守驼峰命名规范
* 类名、接口名: 首字母大写,后面每个单词首字母大写 AdminTest
* 变量名、方法名: 首字母小写、后面每个单词首字母大写 adminTest
* 常量名: 全部大写 ADMIN
2、关键字
public
class
static
void。。。。。
3、字面值
100
"ABC"
'A'
4.14
true、FASE
字面值就是数据
数据显示纾解中是分名别类,他在计算机中也是有类型的【数据类型】
100 属于整数型字面值
“ABC” 属于字符串字面值
‘A’ 属于字符字面值
3.14 属于浮点型字面值
true、FASE 属于布尔字面值
4、变量
- 1、什么是变量
变量本质是哪个是内存的一块空间,这块空间,他有“名字”,“有数据类型”,“有字面值”
变量包含三部分:数据类型,名字,字面值【数据0】
变量是内存储存的最基本的单位
- 2、数据类型的作用:
不同的数据有不同的数据类型,不同的数据类型会分配不同大小的空间
数据类型是知道程序在运行阶段应该分配多大的空间
- 3、变量的要求:变量中储存的数据,必须和变量的数据类型保持一致,不一致时报错
- 4、申明变量的语法:
数据类型 变量名
数据类型:int btye short char long double float 布尔
申明变量后如何赋值:
语法要求: 变量名=字面值
这个可以重新赋值; int i =0 i=100 这个重新复制了
申明变量和赋值一起
语法要求: 数据类型 变量名= 字面值 int i=0 ;int i =100; 这样是不行的,这个是重新申明可一个变量
变量赋值后,可以重新赋值,变量值可以变化,有了变量后空间可以得到重复利用
- 5、通常访问一个变量包括两种方式:
* 第一种 get 获取值
* 第二种 set 设置值
- 6、变量必须先申明在赋值才能访问
1、关于java中的变量
1、在方法体中java代码,是遵守自伤而下的顺序执行的
2、变量的作用域:变量的有效范围:
只需要记住一句话:
出了大括号就不认识了
eg:
int i=0;
for (i = 0; 1 < 10; i++) {} 可以访问i
for (int i = 0; 1 < 10; i++) {} 不能访问i
2、变量的分类:
-
局部变量:在方法体内申明的变量称为 局部变量
-
成员变量:在方法体外申明的变量称为 成员变量
-
类变量(静态变量)
类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变。
静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量。
静态变量在第一次被访问时创建,在程序结束时销毁。
与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。
默认值和实例变量相似。数值型变量默认值是 0,布尔型默认值是 false,引用类型默认值是 null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
静态变量可以通过:ClassName.VariableName的方式访问。
类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致。
5、数据类型:
5.1、基本数据类型:
1、byte:
byte 数据类型是8位、有符号的,以二进制补码表示的整数;
2、short:
short 数据类型是 16 位、有符号的以二进制补码表示的整数
3、int:
int 数据类型是32位、有符号的以二进制补码表示的整数;
4、long:
long 数据类型是 64 位、有符号的以二进制补码表示的整数;
5、float:
float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
6、double:
double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;
7、boolean:
boolean数据类型表示一位的信息;
8、char:
char 类型是一个单一的 16 位 Unicode 字符;
注意:字符串不属于基本数据类型
5.2、引用数据类型
String
Integet 等
所有引用类型的默认值都是null。
转义字符串:
char c1='\n'; //是一个换行符: enter
System.out.println(ii); //输出之后换行
System.out.print(ii); //输出之后不换行
char c1='\t'; //是一个制表符: tab
char c1='\\'; = \
char c1='\''; = '
反斜杠具有转移功能,讲第二个单引号转换成普通的单引号的字符
System.out.println("\"fff\""+c1); "fff"\)
5.3、数据类型的转换
1、八种疾病数据类型中除了布尔类型之外,的7种类型都可以转换
2、小容量向大容量转换,称之为自动类型转换,容量从小到大排序 自动转换
2.1、byte < short(char) < int < long < float < double
2.2、任何浮点类型不管站用多少个字节,都不整数型容量大
char和short可表示的种类数量相同,但chat可以取更大的正整数
2.3、大容量转换成小容量,叫强制类型转换,需要加强制类型转换符,程序才能编译,但肯会随时精度 强制类型转换
2.4、当整数字面值没有超过byte ,short,char可以取值的范围,可以直接赋值给byte short char类型的变量
byte short char 混合运算时,线各自转换成int类型在计算
byte a = 20;
short b =1000;
int c= 1000;
long d=c;
int e=(int)d;
double f=10/3;
long g= 10;
以上都是编译通过的
6、运算符
算数运算符:
a + b = 30
a - b = -10
a * b = 200
b / a = 2
b % a = 0
c % a = 5
a++ = 10
a-- = 11
d++ = 25
++d = 27
关系运算符
a == b = false
a != b = true
a > b = false
a < b = true
b >= a = true
b <= a = false
逻辑运算符
a && b = false
a || b = true
!(a && b) = true
三元运算符
variable x = (expression) ? value if true : value if false
// 如果 a 等于 10 成立,则设置 b 为 20,否则为 30
b = (a == 10) ? 20 : 30;
System.out.println( "Value of b is : " + b );
7、控制语句
选择结构语句
if
if(布尔表达式 1){
//如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){
//如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){
//如果布尔表达式 3的值为true执行代码
}else {
//如果以上布尔表达式都不为true执行代码
}
if(){
}else {
};
switch:
语法:switch(int或者String类型的字面值或者变量)
public class Test {
public static void main(String args[]){
//char grade = args[0].charAt(0);
char grade = 'C';
switch(grade)
{
case 'A' :
System.out.println("优秀");
break;
case 'B' :
case 'C' :
System.out.println("良好");
break;
default :
System.out.println("未知等级");
}
System.out.println("你的等级是 " + grade);
}
}
大括号中的数据不是必须的
循环接口语句
for
for(初始化; 布尔表达式; 更新) {
//代码语句
}
增强for循环
for(声明语句 : 表达式)
{
//代码句子
}
while
while( 布尔表达式 ) {
//循环内容
}
do while
do {
//代码语句
}while(布尔表达式);
o…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
控制顺序语句
break
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。
continue
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
8、方法
方法介绍
1、方法时定义在类体当中的
2、什么是方法:方法就是一个代码片段,,并且这个代码片段可以完成某个功能,并且可以重复使用
3、方法体中不能再定义一个方法
方法的的写法:
修饰符 返回值类型 方法名(参数类型 参数名){ 括号中的是形式参数列表
...
方法体
...
return 返回值;
}
关于修饰符:
1、可选项,不是必须的
2、目前统一写成 public static
3、方法中带static 关键字的话,如何调用
类名.方法名(实际参数列表)
返回值类型:
1、一个方法是可以完成某个特定功能的,这个功能结束之后大多数都是需要
返回最终结果的,执行结果肯能是一个存在的数据,而这个具体的数据就是返回值类型
2、java的返回值类型有哪些
java任意一种类型都可以,包括基本数据类型和所有的引用数据类型
3、形式参数列表:简称形参
形式参数列表是局部变量:int A ;等于
程序的入口:主方法
public static void main(String[] args) {}
形式参数列表: String[]是一种应用数据类型 args 是一个局部变量
其本质和自己写的方法没有区别
接收方法的返回值:比如计算两个数的和,返回值类型为int,所以用int类型的数据接收
int i = sum(1,2)
方法的重载:overload 方法名相同参数不同
功能相似的时候,方法名可以相同
在同一个类中
方法名相同
参数列表不同
数量不同
顺序不同
类型不同
方法的重写 (方法的覆盖):方法名相同,参数列表相同(override )的继承
在重写方法时,需要遵循以下的规则:
(一) 父类方法的参数列表必须完全与被子类重写的方法的参数列表相同,否则不能称其为重写而是重载。
(二) 父类的返回类型必须与被子类重写的方法返回类型相同,否则不能称其为重写而是重载。
(三) Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限。编写过Java程序的人就知道,父类中的方法并不是在任何情况下都可以重写的,当父类中方法的访问权限修饰符为private时,该方法只能被自己的类访问,不能被外部的类访问,在子类是不能被重写的。如果定义父类的方法为public,在子类定义为private,程序运行时就会报错。
(四) 由于父类的访问权限修饰符的限制一定要大于被子类重写方法的访问权限修饰符,而private权限最小。所以如果某一个方法在父类中的访问权限是private,那么就不能在子类中对其进行重写。如果重新定义,也只是定义了一个新的方法,不会达到重写的效果。
(五) 在继承过程中如果父类当中的方法抛出异常,那么在子类中重写父类的该方法时,也要抛出异常,而且抛出的异常不能多于父类中抛出的异常(可以等于父类中抛出的异常)。换句话说,重写方法一定不能抛出新的检查异常,或者比被重写方法声明更加宽泛的检查型异常。例如,父类的一个方法申明了一个检查异常IOException,在重写这个方法时就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。同样的道理,如果子类中创建了一个成员变量,而该变量和父类中的一个变量名称相同,称作变量重写或属性覆盖。但是此概念一般很少有人去研究它,因为意义不大。
方法的递归:这样就死循环了
public static void main(String[] args) {
m1(1);
}
public static void m1(int a){
m1(1);
}
构造方法
方法的内存图分析
- 方法一的内存图分析
public class Student {
int age;
String name;
address add;
int id;
}
public class address {
String street;
String city;
int Zipcode;
}
=========================方法一:或者以下写法,结果都是一样的======================
public static void main(String[] args) {
Student s = new Student();
int stuage=s.age;
s.add = new address();
s.add.city="上海";
System.out.println(s.add.city);
}
// new address(是一个对象)
=========================方法二:或者以下写法,结果都是一样的======================
//a是一个引用,也是一个局部变量
public static void main(String[] args) {
Student s = new Student();
address a = new address();
s.add= a;
a.city="山海";
System.out.println(s.add.city);
}
- 方法二的内存图分析
jvm的介绍:
1、jvm(java虚拟机)主要包含三块内存空间,分别是:栈内存堆内存,方法去内存
2、堆内存和方法区内存个有一个,一个线程一个站内存
3、方法调用的时候,发方法所需额内存空间在栈内存中分配,成为压栈,方法取执行结束后,该方法所属的内存空间释放,称为弹栈
4、栈中主要存储的是方法体当中的局部变量
5、方法的代码片段以及整个类的代码片段都会被储蓄到方法去内存当中,在类加载的时候这些代码会被加载
6、在程序执行过程中使用new运算符创建java对象,储蓄在堆内存当中,对象内部有实力变量,所以实例变量储存在堆内存当中
7、变量分类:
局部变量【在方法体中声明】
成员变量【在方法体外申明】
* 实例变量【前面修饰没有static】
* 静态变量【前面修饰有static】
8、静态变量储蓄在方法区域内存当中
9、三块内存中变化最频繁的是栈内存,最优数据的是方法区域内存,垃圾回收期主要针对的是堆内存
10、垃圾回收期【自动垃圾回收机制,gc机制】什么时候考虑将某个java对象的内存回收
当堆内存的java对象成为垃圾数据的时候, 会被垃圾回收器回收
什么时候堆内存的家吧对象会变成垃圾
没够更多的引用指向他的时候
这个对象无法被方位,应为方位对象只能通过引用的方式访问
空指针:
public static void main(String[] args) {
Student s = new Student();
int stuage=s.age;
address a = new address();
a=null;
s.add= a;
a.city="山海";
System.out.println(s.add.city);
}
如果a=null,会报空指针异常,空引用访问“实例”相关的数据会出现空指针色
三、面向对象,面向过程编程
1、类的定义
语法结构
修饰符列表 class 类名{
属性;
方法
}
引用数据类型
String
student --前提是自己编写了student class类
类体=属性+方法
属性【储存数据采用变量的形式】
由于变量定义在类体重,方法体之外,这种变量称为“成员变量”
所有学生都有学号信息
每个学生的学号不通
所以要访问这个学生的学号必须选穿件对象,通过对象去访问学号
学号信息不能直接通过类去访问,所以这种“成员变量称职为”:实例变量
对象有被称为实例,实例变量右边称之为“对象的变量”
不创建对象,这个学生的编号的内存空间是不存在的,只有穿件对象,内存空间才存在
2、创建对象:
public class Test {
int i=10;//这个称职为实例变量
Student s = new Student();
}
通过一个类可以实例化N个对象
实例化对象的语法 new Student();
new 是java语言当时的一个运符
new运算符的作用是创建对象,在jvm堆内存中开辟新的空间
方法去的内存:在类的加载的时候,class字节代码片段比加载到该内存空间中
栈内存(局部变量):方法代码片执行的时候,会给改方法分配内存空间,在栈内存中压栈
堆内存: new的对象在堆的内存中储存
成员变量没有手动赋值的话,系统会自动赋值:
student是一个引用数据类型
new student是一个学生对象
s是一个局部变量,在栈内存中压栈
s是一个引用
java语言中,程序员不能直接操作堆内存,java没有指针,
java语言中,程序员只能通过“引用”去访问堆内存中对象内部的实例变量
3、访问实例变量的语法
//读数据: 引用.变量名
//修改数据: 引用.变量名=值
public class Test {
public static void main(String[] args) {
Student s = new Student();
int stuage=s.age;
System.out.println(stuage);//间接性读取
System.out.println(s.age);//直接读取
s.age=10;
System.out.println(s.age);// 修改数据
}
}
局部变量在栈内存中储存
成员变量中的实例便利子安在栈内存的家吧对象内部储存
实例变量不能采用 类名.变量名 只能通过引用来进行访问
public static void main(String[] args) {
//對於當前程序來說,student类中的属性是可以随意放问的,缺乏安全性;
Student s = new Student();
int stuage = s.age;
s.name="王思聰";
s.add = new address();
s.add.city="上海";
System.out.println(s.add.city);
System.out.println(s.name);
}
4、面向对象的三大特征
封装
继承
多态
封装步骤:
1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中进行访问
2、一个属性通常访问的时候包括几种方式
第一种:想读取某个属性 get
第二种:想修改某个属性 set
构造方法:
1、构造方法又被称为构造函数、构造器
2、构造方法的语法
修饰符列表 构造方法名(形式参数列表){
构造方法体
}
构造方法的注意向:
2.1、对于构造方法来说,构造方法不需要指定返回值类型
2.2、加上了返回值类型就变成普通方法了
2.3、构造方法的方法名必须和当前的类名相同
普通方法的语法:
修饰符列表 返回值类型 方法名(形式参数列表){
构造方法体
}
3、构造方法的作用:
构造方法存在的意义,通过构造方法的调用,可以创建对象
1、创建对象
2、创建对象的同时,初始化实例变量的内存空间【给实例变量赋值】
4、构造方法的调用
普通方法的调用:方法修饰符中有static的时候
类名.方法名(实参列表)
方法修饰符中没有static的时候
引用.方法名(实参列表)
构造方法的调用:
new 构造方法名(实际参数列表)
构造是有返回值的,但被影藏了,作用是完成对象的创建
5、为什么构造方法的返回值类型不同写
5.1、每一个方法实际执行结束后都有返回值类型,,但这个return 值;这样的语句不需要写,构造方法结束后java程序自动返回值
5.2、并且返回值类型是狗仔方法所在类的诶下,由于构造方法的类型就是本事,所以返回值类型不需要写
5.3、一个默认的类都会有一个默认的五参数的构造方法,一旦编写了有参的构造方法,无参的构造方法不会被影藏;
5.4、构造方法支持重载机制,在一个类中编写多个构造方法,显然这个构造方法已经形成重载机制
在一个构造方法中,可以用this(1,5,6);来调用实参不同的构造方法。
重点:this();这种语法只能出现在第一行。
也就是说:一个构造方法中只能调用一个构造方法
5、参数传递
1、对象和引用
1.1:对象和引用的概念
*对象:目前用new运算符在堆内存中开辟的空间称为对象
*引用:是一个变量,,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了对内存当中的一块空间
*所有实例相关的的访问必须通过“引用”的方式
*引用可以是局部变量,也可以是实例变量
2、参数传递
主要研究和学习的是:方法在调用的时候,涉及到参数传递的问题,到底是怎么传递的呢?
int i =10;
method(i);
给method传递一个i变量,传递的是什么?
-传递的是i变量中的10
i变量是局部变量,本身也占有内存空间,
所以i变量本身也有内存地址,i变量中保存的是10这个字面值
2.1、:参数传递
把main方法中的内存地址传给了add:传递u给add方法的时候,实际上产地的是u变量保存的值,只不过这个是是java对象的内存地址
add(u) 等同于:add(0x1234)
1、方法的实参形参也可以是构造函数
public static void add(User u){
u.age++;
}
传入的是内存地址,修改以后永久修改,不需要return重新修改
注意:u是一个引用,是局部变量,u所指向的是堆内存的一块空间
2、方法调用的时候传递的是变量中保存的“值”
6、this关键字
一:什么时候可以使用this关键字:
1、this关键字:神奇
-this是一个关键字,翻译为这个
-this里面保存了内存地址,指向自身对象
2、引用中:zhangSan.name
在User类中,写一个set方法
public void setName(int name){
//name = name; 报错
this.name = name;
//this=zhangSan,保存了一个内存地址,
指向了自己。
}
3、this是一个引用,this是一个变量,this变量中保存了自己的内存地址,this存储在JVM的堆内存的对应对象中。
100个对象就有100个this
4、当使用zhangSan去访问该对象时,整个过程中出现的this就等于zhangSan
5、没有static关键字的方法被称为实例方法
没有static关键字的变量被称为实例变量
必须要使用引用.方法名()
static的解释:
6、注意,当一个行为/动作执行的过程当中是需要对象参与的,那么这个方法一定要定义为“实例方法”,不要带static关键字
7、this可以用在实例方法中,代表正在执行这个方法的对象
8、this在多数情况下可以省略不写。由于上面的name代表的是当前对象的实例变量,可以省略
9、.static的方法调用不需要对象,直接使用类名,执行过程中直接类名.方法名
例子:
public class constuntur
{
String name;
public void shopping(){
//代表正在执行的这个对象
System.out.println("谁在购物:"+this.name);//c1或者C2谁谁调用就是谁
}
}
public class constomertest {
public static void main(String[] args) {
constuntur c1=new constuntur();
c1.name="张三";
c1.shopping();
constuntur c2=new constuntur();
c2.name="李四";
c2.shopping();
}
}
结论:带有static的方法不能直接访问“实例变量和 实例方法”
通过无参的构造方法来调用有参的
public class constuntur {
private String name;
public void shopping() {
System.out.println("谁在购物:" + name);
}
public constuntur(String name) {
this.name = name;
}
public constuntur() {
方式1 // new constuntur("lei"); 通过这种方式调用无参的构造方法会穿件两个对象
//以上代码可以通过调用另一个构造方法类完成
//但前提是不能穿件新的对象
方式2 this("lei");//只当前的有参的构造方法,避免通过午餐的构造方法穿件了性的对象
}
public static void main(String[] args) {
constuntur c1=new constuntur();
c1.shopping();
constuntur c2=new constuntur("lei");
c2.shopping();
}
this可以用在那
可以使用午餐的构造方法来
二、this什么时候不能省略
1、用来区分实例变量和局部变量的时候不能省略
public constuntur(String name) {
this.name = name;
}
补充:
1、什么时候出现空指针异常?
空引用访问实例相关的数据,因为相关的数据就是对象相关的数据,
空引用访问时没有相关数据,空指针异常。
2、带有static的方法,可以采用类名.方法名的方式访问,也可以用引用.方法名的方式来访问,
只不过用不到这个对象,没有意义,但也能正常运行,不会出现空指针异常
7、Super关键字的使用(出现在继承中)
当需要在子类中调用父类的被重写方法时,要使用super关键字。
(1)super能出现在实例方法和构造方法中。
(2)super的语法是“super.”和“super()”。
(3) super不能出现在静态方法中。
(4) super大部分情况下是可以省略的。
public class MyTest {
public static void main(String[] args) {
Cat c1 = new Cat(3);
System.out.println("名字:" + c1.getName());
System.out.println("年龄:" + c1.getAge());
}
}
//父类,Animal类
class Animal {
//私有属性:名字
private String name;
//setter and getter
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//构造函数
public Animal() {
}
public Animal(String name) {
this.name = name;
}
}
//子类,Cat类
class Cat extends Animal{
//私有字段:年龄
private int age;
//setter and getter
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
//构造函数
public Cat() {
}
public Cat(String name, int age) {
super(name);
this.age = age;
}
}
8、static关键字
一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。
如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。
如果有了static关键字,那么不需要创建对象,直接就能通过类名称来使用它。
无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用。
静态变量:类名称.静态变量
静态方法:类名称.静态方法()
注意事项:
- 静态不能直接访问非静态。
原因:因为在内存当中是【先】有的静态内容,【后】有的非静态内容。
“先人不知道后人,但是后人知道先人。” - 静态方法当中不能用this。
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象。
1.实例变量:
*1.每一个对象都有对应的一个实例变量,要开辟大量内存空间。
如果有一个中国人类
下面country一个带静态一个不带的话,是为了减少内存空间,带static的country储存在方法区中
不带static的话储存在栈中(个人认为都杀不多)
public class Chinese {
int id;
String name ;
static String country="中国"; //带static
public Chinese1() {
}
public Chinese1(int id, String name) {
this.id = id;
this.name = name;
}
public class Chinese {
int id;
String name ;
String country;
public Chinese() {
}
public Chinese(int id, String name, String country) {
this.id = id;
this.name = name;
this.country = country;
}
=country带static=============================
public static void main(String[] args) {
//看起来都一样,创建了太多相同的对象,浪费内存空间
Chinese1 c =new Chinese1(1,"詹三");
System.out.println(c.id+c.name+Chinese1.country);
Chinese1 c1 =new Chinese1(2,"李四");
System.out.println(c1.id+c1.name+Chinese1.country);
}
=country不带static=================
public static void main(String[] args) {
//看起来都一样,创建了太多相同的对象,浪费内存空间
Chinese c =new Chinese(1,"詹三","中国");
Chinese c1 =new Chinese(2,"李四","中国");
Chinese c2 =new Chinese(3,"王五","中国");
}
1.关于java中的static关键字:
1.static单词:静态的
2.static修饰的是静态方法
3.static修饰的变量都是静态变量
4.所有的static修饰的元素都成为静态的,都能使用 “类名.”的方式访问,也能通过“引用.”的方式访问
2、可以使用static关键字来定义“静态代码块”
1.语法格式:
static{
java语句
}
2、静态代码块在类加载的时候执行,并且只执行一次
3、静态代码块在一个类中可以编写多个,并且遵循自上而下的方式进行
4、为什么要学?有什么好处?
静态代码块的作用是什么?怎么用?什么时候用?
*1.和实际需求有关
(1)编写日志。要求在类加载的那一刻执行代码完成日志的记录。
那么这段记录日志的代码就可以编写到静态代码块中,完成日志记录
*2.静态代码块是java为程序员准备的一个特殊时刻,这个特殊的时刻被称为类加载时刻。
若希望在此刻执行一段特殊的程序,这段程序可以直接放到静态代码块中
5、通常在静态代码块中完成数据准备工作。例如:初始化连接池,解析XML配置文件
6、静态代码块(使用的非常少)
class Static1 {
static {
System.out.println("类加载1");
}
static {
System.out.println("类加载2");
}
public static void main(String[] args) {
System.out.println("执行主方法");
}
}
2.在构造方法之前执行一次。
3.可以编写多个,也是遵循自上而下的顺序依次执行
4.这个时机被称为:对象初始化时机
7、实例代码块(用的非常少)
2.在构造方法之前执行一次。
3.可以编写多个,也是遵循自上而下的顺序依次执行
4.这个时机被称为:对象初始化时机
8、方法什么时候声明为静态的?
方法描述的是动作,当所有对象执行这个动作的时候,最终产生的影响是一样的,那么这个
动作已经不再属于某一个对象动作了,可以将这个动作提升为类级别的动作,模板级的动作
*例如:买东西,每个人买的东西不一样,结果不同,定义实例方法a
注意:静态方法中无法直接访问实例变量和实例方法
2.大多数方法都定义为实例方法,一般一个行为或者一个动作在发生的时候,都需要对象的参与
但也有例外:大多数“工具类”中的方法都是静态方法,因为工具类就是方便编程,为了方便方法的调用
继承
四、关于java语言中的继承
1、继承的介绍
-
1.继承是面向对象三大特征之一:封装,继承和多态
-
2.继承基本的作用是:代码复用。但是继承最重要的作用是:有了继承才有了以后方法的覆盖和多态这种机制,减少代码的编写
-
3.继承语法格式:
[修饰符列表] class 类名 extends 父类名{
类体(属性+方法)
}
-
4.java语言当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类
-
5.关于继承中的术语:
B类继承A类 其中:A类称为父类、基类、超类、superclass
B类称为:子类、派生类、subclass -
6.在java语言当中子类继承父类都继承那些数据呢?
* 私有的不支持继承 private * 构造方法不支持继承 * 其他数据都支持继承,都可以被继承
-
7.虽然java语言当中只支持单继承,但是一个类也可以以间接继承其他类
任何一个类默认继承object类
c extends B{
}
B extends A{
}
A extends T{
}
C直接继承B类,但是C类间接继承T A B类
-
8.当一个类没有显示地继承任何类,该类默认继承JAVASE库当中的java.lang.Object类
java语言中任何一个类都有Object类中的特征
-
9.私有的不继承,其他的可以继承,直接把里面的方法拿过来用。
Super关键字的使用(出现在继承中)
当需要在子类中调用父类的被重写方法时,要使用super关键字。
2、方法覆盖
1.Overload回顾方法重载
1、方法重载又被称为overload
2、方法重载什么时候使用?
在同一个类当中,方法完成的功能是相似的,建议方法名相同。
3、什么条件满足后构成方法重载?
在同一个类当中,方法名相同,参数列表不同:类型、顺序、个数
4、方法重载和什么无关
* 和方法的返回值无关
* 和方法的修饰符列表无关
2.方法覆盖Override(方法重写,Overwrite)
-
1.什么时候使用方法重写?
当父类中的方法已经无法满足当前子类的也无需求,子类有必要将父类继承过来的方法进行重写(覆盖); -
2、什么条件满足后会发生方法重写呢?
1、方法覆盖发生在具有继承关系的父子类之间
2、返回值类型相同,方法名相同,形参列表相同就发生覆盖。
3、一定调用覆盖后的方法
4、访问权限不能更低,可以更高
public class Animail {
public void move(){
System.out.println("动物在移动");
}
}
public class Cat extends Animail{
//重写父类的move
public void move(){
System.out.println("cat在移动");
}
}
public class Dog extends Cat{
//重写父类的move
public void move(){
System.out.println("dog在移动");
}
}
public class TestAnimail {
public static void main(String[] args) {
Animail a= new Animail();
a.move();
Cat c= new Cat();
c.move();
Dog d= new Dog();
d.move();
}
}
没重写前都是动物在移动,显然无法实现cat和dog的业务
重写后
父类中:public
子类中只能用public
父类中private
子类中可以public
*抛出异常不能更多,只能更少。
*3、建议方法重写的时候复制粘贴
*4、注意:
私有方法不能继承,所以不能覆盖
构造方法不能继承,所以不能覆盖
静态方法不存在覆盖。
覆盖只针对方法,不谈属性。
3、多态
1.多态的语法:
1、Animal、Cat和Bird三个类之间的关系:
Cat继承Animal
Bird继承Aninal
Cat和Bird没有任何继承关系
2.关于多态的几个概念
向上转型(upcasting)
子类型转换为父类型
又被称为:自动类型转换
向下转型(downcasting)
-父类型转成子类型
又被称为强制类型转换【需要添加强制类型转换符】
转型的前提:*要想通过编译,必须要有继承关系,没有继承关系,程序是无法通过的。
3.Animal a2 = new Cat();
可以,*Animal和Cat之间存在继承关系,Animal是父类,Cat是子类
*new Cat()创建的对象类型是Cat,a2这个引用的数据类型是Animal,可见他们进行了类型转换
*子类型转换为父类型,向上转型,自动类型转换
4.java程序永远都分为编译阶段和运行阶段
先分析编译阶段,再分析运行阶段,编译无法通过,无法运行
*编译阶段检查a2这个引用数据类型Animal,由于Animal.class
字节码中有move()方法,所以编译通过了。
这个过程我们称为静态绑定,编译阶段绑定
只有静态绑定成功之后才能运行
*运行的时候,JVM堆内存当中真实创建的对象是Cat对象,那么以下程序在运行阶段
一定会调用Cat对象的Move()方法,此时发生了程序的动态绑定
5.无论Cat类有没有重写move方法,运行阶段一定调用的是Cat对象的move方法,应为底层真是对象就是Cat对象
6.父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的形态/状态
这种机制可以成为一种多态语法机制。
7.静态绑定成功后才能进行动态绑定。
4、多态进阶:
1.不存在继承关系的类型:
Bird c1 = Cat();
Bird Cat 都属于Animal的子类,但是cat and bird之间没有继承关系
所有不能
2.如果说要调用父类型没有的方法?
Animal a1 = new Cat();
Cat里有一个catchMouse方法;
a1无法直接调用,应为a2的类型是Animal,没有这个方法怎么办?
*可以将a1强制类型转换为Cat
a1的类型是Animal(父类),转换为Cat类型(子类),被称为向下转型(downcasting)
public class Animail {
public void move(){
System.out.println("动物在移动");
}
}
public class Cat extends Animail{
public void move(){
System.out.println("cat在移动");
}
}
public class Dog extends Animail{
public void move() {
System.out.println("dog在移动");
}
//这个个在子类中特有的方法
public void dogcat(){
}
}
public class TestAnimail {
public static void main(String[] args) {
Animail a= new Animail();
a.move();
Cat c= new Cat();
c.move();
//父类型的应用允许执行子类型的对象
Animail d= new Dog();
d.move();//编译器的绑定,无法访问到dogcat
Dog c2= (Dog)d; //想要访问的话的做强制类型转换
//d.dogcat();
c2.dogcat();
}
}
注:向下转型也需要两种类型之间有继承关系。要加上强制类型转换符
-
什么时候需要向下转型呢?
当调用的方法或者访问的类型是子类型中特有的,在父类型当中不存在,必须进行向下转型
-
怎么转?
Cat a2 = (Cat)a1;
3.类型转换异常:如果说有一个代码:
Animal a3 = new Bird();
Cat c3 = (Cat)a3;
-
编译阶段没问题,因为编译器认为a3是Aninal(父),转换为c3(子)
语法合格 -
程序虽然编译通过了,但是程序在运行阶段会出现异常,应为JVM堆内存
当中真实存在的是Bird类型,Bird类型无法转换为Cat对象,因为两种类型没有继承关系
此时出现了著名的异常:java.lang.ClassCastException异常:类型转换异常
这种异常只有在强制类型转换的时候出现异常
怎么避免这种异常?instanceof 的使用
- 1、以上异常只有在强制类型转换的时候会发生,也就是说,向下转型存在安全隐患
- 2、向上转型只要能编译通过,运行一定不会出问题
- 3、向下转型编译通过,运行可能出问题
- 4、怎么避免乡下转型出现的类型转换异常?
使用instanceof运算符可以避免以上异常 - 5、instanceof怎么用?
5.1、语法格式
引用 instanceof 数据类型名
5.2、以上运算符的执行结果类型是布尔类型,结果可能是true/false
5.3、关于运算结果true/false
假设(a instanceof Animal)
true:表示a这个引用指向的对象是一个animal类型
false:表示a这个引用只想的对象不是一个animal类型
- 6、如果想要安全执行向下转换:
//Cat c3 = (Cat)a3;
if (a3 instanceof Cat){
Cat c3 = (Cat)a3;
}else{
System.out.println("错误!");
}
-
7.java规范中要求,在进行强制类型转换之前,建议使用instanceof运算符进行判断,避免ClassCaseExpection异常的出现
4.调试debug的方法:断点
5、多态在实际开发中的作用
1.多态在实际开发中的作用?(以主人喂养宠物为例说明)
*1.分析:主人喂养宠物这个场景要实现需要进行类型的抽象
-主人【类】
-主人可以喂养宠物,所以主人有喂养这个动作
-宠物【类】
-宠物有吃东西的动作
*2.定义好类,然后将类实例化为对象+,给一个环境驱使,让哥哥对象之间协作起来形成一个系统
*3.提高程序的扩展力:
降低软件的耦合度【解耦合】,提高程序的扩展力
master主人类面向一个抽象的Pet类型,而不是面向具体的Dog、Cat类型
在使用的时候可以使用向上转型,子类转换为父类。
2.即多态的作用是降低程序耦合度,提高扩展力。
*核心:面对抽象编程,不要面向具体编程。
面向对象的例子
public class Cat extends Pet {
//重写了Pet
public void eat(){
System.out.println("猫爱吃鱼");
}
}
public class Dog extends Pet {
//重写了Pet
public void eat() {
System.out.println("宠物小狗吃骨头");
}
}
public class Master {
/*
以下这个方法扩展了很差,没使用多台时,每个都很麻烦
public void feed(Cat c){
c.eat();
}
public void feed(Dog d){
d.eat();
}
*/
//使用多态
//Pet pet=new Cat ;Pet pet=new Dog 是一个父类型的应用,扩展性强
//mast面向的是一个抽象的变成好处是耦合度低,扩展性极强
public void feed(Pet pet){
pet.eat();
}
}
//使用多态是新增一个类
public class Pet {
public void eat<