day20---前19天内容总结
1.语言基础
1.Java开发环境、JVM、JRE、JDK
-
Java开发环境
-
编译运行过程:
-
编译器:.Java源文件,经过编译,生成.class字节码文件
-
运行期:JVM加载.class并运行
特点:跨平台,一次编译到处使用
-
-
-
JVM:Java虚拟机
加载.class并运行.class
-
JRE:Java运行环境
除了包含JVM以外还包含运行Java程序所必须的环境
-
JDK:Java开发工具包
除了包含JRE以外还包含了开发Java程序所必须的命令工具
JDK=JRE+编译、运行等命令工具
说明:
-
运行Java程序的最小环境为JRE
-
开发Java程序的最小环境为JDK
-
-
驼峰命名
-
大驼峰
-
特点:第一个字母大写,后边也大写
-
应用:类名、函数名、属性名、命名空间
-
-
小驼峰
-
特点:第一个字母小写,后边大写
-
应用:变量
-
-
2.变量、八种基本数据类型、类型间的转换
-
变量:
-
声明:相当于开户
-
初始化:第一次赋值,相当于给账户存钱
-
使用:使用账户的钱
int a;
int a,b,c;
//初始化
int a =250;
int b;
b=1000;
//使用
int a=5;
int b=a+10;
System.out.println(b); -
变量在用之前必须声明并初始化
-
命名:
-
只能包含数字、字母、_和$符号,且不能以数字开头
-
严格区分大小写
-
不能使用关键字
-
允许中文名,但不建议,建议“英文的见名知意”
-
-
-
八种基本数据类型
int\long\double\boolean\char\byte\float\short
-
int:整型,4个字节,-21个多亿到21个多亿
-
整数直接量默认为int类型,但是不能超范围,否则编译错误
-
两个整数相除,结果还是整数,小数位无条件舍去
-
整数运算时,若超出int范围则发生溢出(溢出不是错误,但需要避免)
-
-
long:长整型,8个字节
-
长整型直接量需要在数字后面加L或者l
-
运算时若可能溢出,建议在第一个数字后加L
-
-
double:浮点型,8个字节
-
浮点数直接量默认为double型,若想表示float须在数字后面加F和f
-
double与float型数据参与运算时,有可能出现舍入误差,精准场合不能使用
-
float是单精度类型,精度是8位有效数字,取值范围是10的-38次方到10的38次方,float占用四个字节的存储空间
double是双精度类型,精度是17位有效数字,范围是10的-308次方到10的308次方,double占用8个字节的存储空间
-
-
boolean:布尔型,1个字节
-
char:字节型,2个字节
-
采用Unicode字符集,一个字符对应一个码
表现的形式是字符char,但是本质上是码int(0到65535之间)
ASCLLII码:’a‘--97 ‘A’--65 ‘0’---48
-
字符型直接量必须放在单引号中,且只能有1个
-
特殊符号需通过\来转义
-
-
-
类型间的转换
-
基本类型由小到大为:
byte\short\char->int->long->float->double
-
注意:这里的大小指的不是占了多少字节的大小而是取值范围,且boolean类型不参与类型转换
byte、short、char相互之间不转换,它们参与运算首先转换为int类型
-
两种方式:
-
自动/隐式类型转换:小类型到大类型,范围小的数据类型直接转换为范围大的数据类型
-
强制类型转换:大类型到小类型
int a =5;
long b= a;//自动类型转换
int c =(int)b;//强制类型转换
•
•
long d = 5;//自动类型转换
double e = 5;//自动类型转换
•
•
•
long f = 10000000000L;
int g = (int)f; //强制类型转换
System.out.println(g); //1410065408,强转有可能发生溢出
double h = 25.987;
int i = (int)h; //强制类型转换
System.out.println(i); //25,强转有可能丢失精度 -
两点规则
-
整数直接量可以直接赋值给byte(范围为-128到127之间),short,char,但是不能超出范围
-
byte,short,char型数据参与运算时,系统一律自动将其转换为int在运算
byte b1 = 5; //byte的范围为-128到127之间
byte b2 = 6;
byte b3 = (byte)(b1+b2);
•
System.out.println(2+2); //4
System.out.println(2+'2'); //52,2加上'2'的码50
System.out.println('2'+'2'); //100,'2'的码50,加上'2'的码50
-
-
###
-
3.运算符、分支结构
-
运算符
-
普通四则运算符+,-,*,/
-
取余%,余数为0表示整除
-
自增自减运算符
-
可以改变变量自身的值
-
前缀式:++a,先改变自身的值,再参与运算
-
后缀式:a++,先参与运算,再改变自身的值
-
注意:
-
单独使用时,两者的值相同
-
被使用时,++a的值为a+1;a++的值为a
-
-
比较运算符
-
比较运算符最终的结果是布尔类型的
-
==两边的值是否相等,!=为不相等
-
-
逻辑运算符
-
&&:与
-
||:或
-
!:非
-
-
赋值
=,+=,-=,*=,/=,%=
-
拼接功能
-
两边都为数字,做加法运算
-
若两边出现字符串,则字符串连接
-
任何类型与字符串相连,结果都会变为字符串类型---同化作用
-
-
条件运算符:三目运算符
-
语法:Boolean?数1:数2
-
执行过程:
整个表达式是有值的,值只能是?后面的值之一
计算Boolean的值:
若为true,整个表达式的值为?号后的数1
若为false,整个表达式的值为:号后的数2
-
-
-
-
分支结构
-
if(){}else(){}
-
嵌套分支结构
if(判断条件1){
符合判断条件1,执行此处代码,不符合,继续向下判断
}else if(判断条件2){
符合判断条件2,执行此处代码,不符合,继续向下判断
}else if(判断条件3){
符合判断条件3,执行此处代码,不符合,继续向下判断
}else{
保底选项,以上条件均不符合的情况下,执行此处代码
}
-
-
选择结构
-
小括号中变量支持的类型: byte\ short\ char\ int\ String\枚举类型
-
注意: 如果配置了default默认选项,而且没有任何的case被匹配到,就会执行default这个“保底选项”,default可以写在switch里的任何地方,但无论写在哪儿,都一定是先匹配case,当所有case都未匹配时才执行
-
case的个数 是否加break 是否加default全部都是可选的,根据自己的具体业务做决定
-
小括号中变量的类型必须与case后value的类型一致
-
执行顺序:先拿着变量的值,依次与每个case后的值做比较,如果相等,就执行case后的语句 若这个case后没有break,就会继续向下执行下一个case,如果一直没有遇到break,就会发生穿透现象,包括default
-
switch (变量名){
case value1 : 操作1;break;//可选
case value2 : 操作2;break;//可选
case value3 : 操作3;break;//可选
case value4 : 操作4;break;//可选
default:保底选项;//可选
}
-
4.循环结构
-
循环三要素:
-
循环变量的初始化
-
循环变量的条件(以循环变量为基础)
-
循环变量的改变
循环变量:在整个循环变量中反复改变的那个数
-
-
循环结构
-
while结构
-
语法:
while(boolean){
语句块
} -
执行过程
-
先判断boolean的值,若为true则执行语句块
-
再判断boolean的值,若为true则再执行语句块
-
再判断boolean的值,若为true则再执行语句块,如此反复,直到boolean的值为false时,while循环结束
-
-
-
do...while结构
-
实例:猜大小
import java.util.Scanner;
public void Guessing{
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
int num=(int)(Math.random()*1000+1);
int guess;
do{
System.out.println("请输入一个数");
guess=scan.nextInt();
if(guess>num){
System.out.println("大了");
}else if(guess<num){
System.out.println("小了")
}else{
System.out.println("猜对了")
}
}
while(guess!=num)
}
}
-
-
for结构
-
注意:
-
写法小窍门:从哪儿开始,到哪儿结束,循环变量如何变化
-
for循环执行的次数,取决于循环变量可以取到几个值
-
for中的循环变量times的作用域仅在当前for中
-
-
for...each:
不使用下标变量就可以顺序的遍历整个数组
-
-
-
三种结构如何选择
-
先看循环是否与次数相关
-
相关:---------for
-
无关:---------再看要素1,3是否相同(
第一要素:开始条件;
第二要素:循环条件;
第三要素:更改条件)
-
若相同------------------直接上do...while
-
先循环后判断
do-while循环一定会执行一次,然后再判断,如果符合条件,再执行后面的循环
-
-
若不同------------------while
-
先判断再循环(数字叠加)
-
-
-
-
-
break---continue
-
作用:
主要作用都是停止循环
-
区别:
-
注意:
-
只能在循环体和switch语句体内使用break
-
不管是哪种循环,一旦在循环体中遇到break,系统将完全结束循环,开始执行循环之后的代码。
-
当break出现在循环体中的switch语句体内时,起作用只是跳出该switch语句体,并不能终止循环体的执行。若想强行终止循环体的执行,可以在循环体中,但并不在switch语句中设置break语句,满足某种条件则跳出本层循环体。
-
continue语句的作用是跳过本次循环体中剩下尚未执行的语句,立即进行下一次的循环条件判定,可以理解为只是中止(跳过)本次循环,接着开始下一次循环。
-
注意:
-
continue语句并没有使整个循环终止。
-
continue 只能在循环语句中使用,即只能在 for、while 和 do…while 语句中使用
-
-
-
嵌套循环
-
嵌套for循环
外层循环控制的是轮数,内层循环控制的是每一轮中执行的次数 对于图形而言,外层循环控制的是行数,内层循环控制的是列数
-
5.数组
-
创建:
-
根据数组的类型与长度开辟一块连续的内存空间
-
对数组中的每个元素进行初始化,比如int数组的默认值就是0
-
生成数组唯一的一个地址值,交给应用类型变量a来保存
-
后续可以根据数组的下标再来操作数组中的具体元素 注意: 数组名a这个变量,保存的是数组的地址,不是数组中的具体元素
-
-
数组的工具类Arrays
-
toString(数组名) : 除了char类型的数组以外,其他类型的数组想要查看具体元素,需要使用本方法,否则打印的是地址值
-
copyOf(原数组名,新数组的长度) : 用来实现数组的复制 扩容 缩容 如果新数组的长度 > 原数组长度,就扩容,反之,则缩容,如果两者长度一致,就是普通的复制数组 注意:一定是创建了新数组,而不是对原数组的长度做操作
-
-
复制:
-
方法一:System.arraycopy(a,0,b,0,4);
a:源数组
0:源数组开始复制的位置
b:目标数组
0:目标数组开始接受复制的位置
4:复制的长度
-
方法二:引入小零件Array , Array.copyOf(a,b)
a:源数组
b:新数组长度
-
-
排序:
升序:Arrays.sort(arr)
倒序:从最后一项开始
for (int i=a.length-1;i>=0;i--){
System.out.println(a[i]);
}
6.方法
-
定义
-
用于封装一段特定的逻辑功能
-
方法尽可能独立,只干一件事
-
-
五要素:
-
修饰词 public static
-
返回值类型
-
无返回值:类型一般设计为void
-
有返回值:类型设计为特定的数据类型
-
有无返回值的区分:
方法被调用后数据是否还会被使用
-
-
方法名(参数列表){方法体}
-
注意:方法定义不能套娃,只能并列;但是方法调用可以套用
-
调用:有无返回值
-
无返回值:方法名(有参传参)
//无返回值,无参数
public static void say(){
System.out.println("雷浩啊");
}
•
//调用
say();
//无返回值,有参数
public static void plus(int gold){
double mon= (double) (0.068)*gold;
System.out.println("需要花费¥"+mon+"元");
•
}
//调用
plus(1000); -
有返回值:数据类型 变量 =方法名(有参传参)
//有返回值,无参数
public static double getNum( ){
return 8.88;
•
}
//调用
double b=getNum();
System.out.println(b)
//有返回值,无参数---数组返回值
public static int[] testArray(){
int [] arr=new int[10];
for (int i =0;i<arr.length;i++){
arr[i]=(int)(Math.random()*100);
•
}
return arr;
}
//调用并排序
import java.util.Arrays;
int [] t=testArray();
System.out.println(t.length);
System.out.println("");
for (int i=0;i<t.length;i++){
System.out.println(t[i]);
}
Arrays.sort(t);
System.out.println("");
for (int i=0;i<t.length;i++){
System.out.println(t[i]);
}
//有返回值,有参数
public static int maxPlus(int num1,int num2){
int num =num1+num2;
return num;
}
//调用
int a=maxPlus(5,6);
System.out.println(a);
//或者
int e=5,f=6;
int b=maxPlus(e,f);
System.out.println(b);
-
-
return
return 值:结束方法并将值返回给调用方
return;结束发方法的执行
-
2.面向对象
1.类和对象、方法的重载
1.类
-
定义:类别/类型,代表一类个体
-
关系:类是对象的模板,对象是类的具体实例
-
类是自己创建的引用数据类型
-
创建:
-
类的创建
定义类通过关键字class来定义,类是一类事物的抽象
public class a { }//a为类名
-
Java中一个文件只包含一个类
-
访问类,打点.调用---------zs.
-
2.对象
-
定义:软件中真实存在的单个个体/东西
-
对象的属性/特征------------------变量
-
对象的行为/功能------------------方法
-
对象之间相互独立,互不影响
-
类是对象的模板,对象是类的具体实例
-
对象具有类的所有属性和功能
-
创建:
对象的创建
通过new关键字触发构造函数生成,对象是根据类创建出来的实例,因此把创建对象也成为“实例化”
Student zs=new Student();Student:数据类型zs:引用类型变量,后期简称为引用=:指向new Student:对象
-
访问类,打点.调用---------zs.
3.方法的重载
-
英文命名:overload/overloading
package ooday01;public class Aoo {
void show(){};
void show(String name){};
void show(int age){};
void show(String name ,int age ){};
void show(int age,String name){}; //错误
//void show(){return 0}; //编译错误,重载与返回值类型无关
// void show(String address){};//编译错误,重载与参数名称无关} -
作用:更加方便的使用方法
-
方法的签名=方法名+参数列表
-
发生在同一类中,方法名相同,参数列表不同
-
编译器在编译时会根据方法的签名自动绑定方法
2.构造方法、this
1.构造方法
-
又名构造函数,构造器
-
作用:给成员变量赋初始值
-
调用:在创建(new)对象时被自动调用
-
构造方法可以重载
-
与类同名,没有返回值类型
package ooday02;
•
public class Student {
String name;
int age;
String address;
•
void sayHi() {
System.out.println("我的名字是" + name + ",今年" + age + "岁了,家住" + address);
} //构造函数
•
Student(String name1, int age1, String address1) {
name = name1;
age = age1;
address = address1;
}
}//调用package ooday02;
•
public class TestStudent {
public static void main(String[] args) {
Student zs = new Student("张三", 18, "jiangsu");
zs.sayHi();
Student ls = new Student("里斯", 20, "hebei");
ls.sayHi();
}
}
2.this
-
只能用在方法中 ,方法中访问成员变量之前默认有个this
-
指代当前对象,哪个对象调用它就指代哪个对象
-
this.成员变量名-------访问成员变量
-
局部变量,只在当前方法范围
-
成员变量与局部变量可以同名
-
使用的时候默认就近原则
-
访问成员变量时this不能省略
-
-
实例
public class Student { String name; int age; String address;
void.sayHi(){System.out.println("我的名字是"+name+",今年"+age+"岁了,家住"+address); }
Student(name,age,address){
this.name =name;
this.age=age;
this.address=address }}
//调用public
class ConsDemo { public static void main (String[] args) {
Student zs=new Student("张三",18,"jiangsu");
zs.sayHi();
Student ls=new Student("里斯",20,"hebei");
s.sayHi(); }}
3.引用类型数组、继承、super
1.引用类型数组
与基本类型数组的区别
-
给数组元素赋值必须new一下
-
若想访问对象数据必须通过数组元素打点
Student stus=new Student[3];stus[0]=new Student("zhangsan",23,"ls");
stus[1]=new Student('lisi',25,"gh");
stus[2]=new Student("wangwu",19,"fh");
System.out.println(stus[0].name);
for(int i=0;i<stus.length;i++){ System.out.println(stus[i].name)}
2.继承
-
作用:代码复用
-
通过extends来继承
-
继承要符合is(是)的关系,不能为了复用代码就乱继承
-
超类/父类:共有的属性和行为
-
派生类/子类:特有的属性和行为
-
派生类/子类既能访问自己的,也能访问超类,但是超类不能访问派生类
-
一个超类可以有多个派生类,但是派生类只能有一个超类
-
继承具有传递性
-
继承的是超类中的成员变量和普通方法,而不包括构造方法
超类的构造方法是被派生类通过super来调用
-
Java规定:构造派生类之前必须先构造超类
-
在派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
-
在派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
-
super()调用超类构造方法,必须位于派生构造方法的第一行
-
3.super
-
定义:指代当前对象的超类对象
-
用法:
-
super.成员变量名-------------访问超类的成员变量
-
super.方法名()-----------------调用超类的构造方法
-
super()----------------------------调用超类的构造方法
-
4.向上造型、方法的重写
1.向上造型
-
超类型的引用指向派生类的对象
-
java规定:能点出什么,看引用类型
-
意义:实现代码复用
-
当多种角色能干的事是同一件时,可以将那多种角色造型到超类数组中,统一访问
-
2.方法的重写
-
发生在父子类中,方法名相同,参数列表相同
-
重写方法被调用时,看对象的类型
-
重写遵循“两同两小一大”原则
-
两同:
-
方法名相同
-
参数列表相同
-
-
两小:
-
派生类方法的返回值类型小于或等于超类方法的
-
void和基本类型时,必须相等
-
引用类型时,小于或等于
-
-
派生类方法抛出的异常小于或等于超类方法的
-
-
一大:
派生类方法的访问权限大于或等于超类方法的
-
3.重写与重载的区别
-
重写(override):发生在父子类中,方法名相同,参数列表相同
--------用于在派生类中修改超类中所声明的方法
-
重载(overload):发生在同一类中,方法名相同,参数列表不同
--------完全不同的方法,只是方法名正好相同
5.package和import、访问控制修饰符、static、final
1.package
-
package:声明包
-
避免类的命名冲突
-
同包的不能同名
-
类的全称:包名.类名
-
包名常常用层次结构,建议所有字母都小写
-
2.import
-
同包中的类可以直接访问 不同包中的类不能直接访问,若想访问:
-
先import声明类,再访问类------建议
-
类的全称-----------------------------太繁琐,不建议
-
3.访问控制修饰符
-
作用:保证数据的安全
-
public:公开的,任何类
-
private:私有的,本类
-
protected:受保护的,本类、派生类、同包类
-
默认的:什么也不写,本类、同包类
说明:
-
类的访问权限只能是public或默认的
-
类中成员的访问权限如上4种都可以
-
访问权限由高到低为:public>protected>默认>private
-
4.static
1.成员变量(实例变量、静态变量)
-
实例变量:
-
没有static修饰
-
属于对象
-
存储在堆中
-
new多少个,存在多少个
-
通过引用(对象)点访问
-
代码:
Student zs=new ...zs.name/age/address
-
-
静态变量:
-
由static修饰
-
属于类
-
存储在方法区
-
只存一份
-
通过类点访问
-
何时用:所有对象所共享的数据(图片、音频、视频等)
-
代码:
class Aoo { int a;}//调用Aoo.a
-
-
区别:
-
初始化:静态块-----初始化静态变量;
构造方法--初始化实例变量;
-
2.静态方法
-
由static修饰
-
属于类,存储在方法区中,只有一份
-
常常通过类名点来访问
-
静态方法中没有隐式this传递
-
何时用:方法的操作与对象无关
-
public class StaticDemo {
public static void main (String[] args){
Moo.test();
}
}
//演示静态方法
class Moo {
int a;//实例变量(对象点来访问)
int b;//静态变量(类名点来访问)
void show() {//有隐式this
System.out.println(this.a);
System.out.println( Moo.b);
}
static void tset(){//没有隐式this
//System.out.println(this.a);//编译错误.原因:静态方法中没有隐式this传递,没有this意味着没有对象,而实例变量a必须通过对象点来访问
System.out.println( Moo.b);
}
}
•
//演示静态方法什么时候用
class overwatch{
int a; //对象属性a
void show(){
//在show方法中用到了对象的属性a,意味着show()方法与对象有关,所以不能设计为静态方法
System.out.println(a);
}
//在plus方法中没有用到对象的属性a,意味着plus()方法与对象无关,所以可以设计为静态方法
static int plus(int num1,int num2){
int num=num1+num2;
return num;
}
}
•
3.静态块
-
由static修饰
-
属于类,在类中被加载期间自动执行,一个类只能被加载一次,所以静态块只执行一次
-
何时用:加载/初始化静态资源(图片、音频、视频等)
-
代码
public class static {
public static void main(String[] args){
Aoo o1=new Aoo;
Aoo o2=new Aoo; } }
//演示静态块
class Aoo {
static { System.out.println("静态块"); }
Aoo(){ System.out.println("构造方法"); }}
4.补充
-
数据(成员变量)私有化(private),行为(方法)大部分公开化(public)
-
成员变量分两种:
-
实例变量:没有static修饰,属于对象的,存储在堆中,有几个对象就有几份 通过引用(对象)点来访问
-
静态变量:由static修饰,属于类的,存储在方法区中,只有一份 通过类名点来访问
-
6.static final常量、抽象方法、抽象类
1.static final常量
-
必须“声明同时初始化”
-
类名点来访问,不能被改变
-
建议:常量所有字母必须大写,多个单词用_隔开
-
编译器在编译时常会将常量直接替换成具体的数值,效率高
-
何时用:数据不变,经常使用
-
代码
public Aoo { public static int a=5; public static final int b=5;}
2.抽象方法
-
由abstract修饰
-
只有方法的定义,没有具体实现的方法,连{}都没有
3.抽象类
-
由abstract修饰
-
包含抽象方法的类必须是抽象类
-
抽象类不能被实例化(new 对象)
-
抽象类是需要被继承的,派生类:
-
重生所有抽象对象------------------变不完整为完整
-
也声明为抽象类---------------------一般不这么用
-
-
抽象类的意义:
-
封装共有的属性和行为----------------代码复用
-
为所有派生类提供统一的类型-------向上造型
-
可以包含抽象方法,为所有派生类提供统一的入口(能点出来),
派生类的行为不同,但入口是一致的,同时相当于定义了一个标准(强制重写)
-
7.成员内部类、匿名内部类
1.成员内部类
-
应用率低
-
类中套类,外面的成为外部类,内部的成为内部类
-
内部类只服务于外部类,对外不具备可见性
-
内部类对象通常在外部类创建
-
内部类中可以直接访问外部类的成员(包括私有的)
内部类有个隐式的引用指向了创建它的外部类对象:外部类名.this
2.匿名内部类
-
应用率高,大大简化代码
-
若想创建一个类(派生类)的对象,并且对象只被创建一次,可以做成匿名内部类
-
在匿名内部类默认外面的变量为final的---Java规定
-
内部类有独立的.class吗?答:有
8.接口
-
是一种引用类型数据
-
由interface定义
-
只能包含常量和抽象方法
-
接口不能被实例化(new对象)
-
接口是需要被实现/继承的,实现类/派生类
---必须重写所有方法
-
一个类可以实现多个接口,用逗号分隔,若又继承又实现时,应先继承后实现
-
接口可以继承接口
//接口的演示
public class InterfaceDemo {
public static void main(String[] args) {
//Inter5 o1 = new Inter5(); //编译错误,接口不能被实例化
Inter5 o2 = new Doo(); //向上造型(可以造型为它所实现的接口)
Inter4 o3 = new Doo(); //向上造型
}
}
•
//演示接口继承接口
interface Inter4{
void show();
}
interface Inter5 extends Inter4{
void test();
}
class Doo implements Inter5{
public void test(){}
public void show(){}
}
•
//演示接口多实现
interface Inter2{
void show();
}
interface Inter3{
void test();
}
abstract class Boo{
abstract void say();
}
class Coo extends Boo implements Inter2,Inter3{
public void show(){}
public void test(){}
public void say(){}
}
•
//演示接口的实现
interface Inter1{
void show(); //访问权限默认是public
void test();
}
class Aoo implements Inter1{
public void show(){} //重写接口中的抽象方法,访问权限必须是public
public void test(){}
}
•
//演示接口的语法
interface Inter{
public static final int NUM = 5; //接口中成员的访问权限只能是public的
public abstract void show();
int COUNT = 6; //默认public static final
void say(); //默认public abstract
//int number; //编译错误,常量必须声明同时初始化
//void test(){} //编译错误,抽象方法不能有方法体
}
9.多态
-
意义:
-
同一类型的引用指向不同的对象时,有不同的实现---所有抽象方法都是多态的
-----行为的多态
-
同一个对象被造型为不同类型时,有不同的功能---所有对象都是多态的
-----对象的多态
-
-
向上造型/自动类型转换
-
超类型的引用指向派生类的对象
-
能点出什么,看引用类型
-
能造型成为的数据类型:超类+所实现的接口
-
-
强制类型转换,成功的条件只有如下两种
-
引用所指向的对象,就是该类型
-
引用所指向的对象,实现了该接口或者继承了该类
-
-
强转时若不符合上述条件,则发生ClassCastException类型转换异常;因此强转前先通过instanceof判断引用的对象是否是该类型
public class MultiTypeDemo {
public static void main(String[] args) {
Aoo o = new Boo(); //向上造型
Boo o1 = (Boo)o; //引用o指向的对象就是Boo
Inter o2 = (Inter)o; //引用o指向的对象实现了Inter接口
//Coo o3 = (Coo)o; //运行时发生ClassCastException类型转换异常
if(o instanceof Coo){ //false
Coo o4 = (Coo)o;
}else{
System.out.println("o不是Coo类型");
}
}
}
•
interface Inter{
}
class Aoo{
}
class Boo extends Aoo implements Inter{
}
class Coo extends Aoo{
}
•
10.内存管理、面向对象总结、String入门
1.内存管理
-
由JVM来管理
-
堆:new出来的对象(包括成员变量,即实例变量)
-
垃圾:没有任何引用所指向的对象
垃圾回收器(GC)不定时到内存中清扫垃圾,回收过程是透明的(看不到的),不一定一发现垃圾就立刻回收,通过调用System.gc()可以建议JVM尽快调用GC回收
-
实例变量的生命周期:
创建(new)对象时存储在堆中,对象被回收时一并被回收
-
内存泄漏:不再使用的对象没有被及时回收,严重的泄露会导致系统的崩溃
建议:不再使用的对象应及时将引用设置为null
-
-
栈:存储正在调用的方法中的局部变量(包括方法的参数)
-
调用方法时,会在栈中为该方法分配一块对应的栈帧,栈帧中存储局部变量(包括方法的参数),方法调用结束时,栈帧会被自动清除,局部变量一并被清除
-
局部变量的生命周期:
调用方法时存储在栈中,方法调用结束时与栈帧一并被清除
-
-
方法区:
-
存储.class字节码文件(包括静态变量、所有方法)
-
方法只有一份,通过this来区分具体的访问对象
-
-
成员变量:写在类中,方法外----有默认值
-
局部变量:方法中------------------没有默认值
-
数组也是一个对象,所以数组对象也存储在堆中,将数组的元素当作成员变量一并存储在堆中
2.面向对象总结
-
封装
-
类:封装的是对象的行为和属性
-
方法:封装的是具体的业务逻辑的实现
-
访问控制修饰符:封装的是具体的访问的权限,以保护数据安全
-
-
继承
-
作用:代码复用
-
超类:所有派生类所共有的行为和属性
接口:部分派生类所共有的行为和属性
派生类:派生类所特有的行为和属性
-
单一继承,多接口实现,具有传递性
-
-
多态:
-
行为多态:所有抽象方法都是多态的(通过方法的重写实现的)】
-
对象多态:所有对象都是多态的(通过向上造型来实现)
-
向上造型、强制类型转换、instanceof判断
-
3.String入门
-
String字符串类型
-
java.lang.String使用final修饰,不能被继承
-
Java中的String在内存中采用Unicode编码方式,任何一个字符占用两个字节的编码
-
字符串底层封装的是一个字符数组
-
字符串一旦创建,对象内容永远无法改变,但字符串引用可以重新赋值---不变对象
-
-
常量池:
-
Java对字符串有一个优化措施:字符串常量池(堆中)
-
java推荐我们使用字面量/直接量方式来创建字符串,并且会缓存所有以字面量/直接量的形式创建的字符串对象到常量池,当使用相同字面量字符串再创建对象时,将复用常量池的对象以减小内存开销,从而避免内存堆积大量内容相同的字符串对象
-
package ooday10;
//String的演示
public class StringDemo {
public static void main(String[] args) {
String s1 = "123abc"; //堆中创建一个123abc对象,常量池中存储这个对象的引用
•
//编译器在编译时,若发现是两个字面量连接,
//则直接运算好并将结果保存起来,如下代码相当于String s2="123abc";
String s2 = "123"+"abc"; //复用常量池中的123abc对象
System.out.println(s1==s2); //true
•
String s3 = "123";
//因为s3不是字面量,所以并不会直接运算结果
String s4 = s3+"abc"; //会在堆中创建新的123abc对象,而不会重用常量池中的对象
System.out.println(s1==s4); //false
•
•
•
•
•
•
•
/*
使用字面量来创建字符串对象时,JVM会检查常量池中是否有该对象:
1)若没有,则会创建该字符串对象并存入常量池中
2)若有,则直接将常量池中的对象返回(不会再创建新的字符串对象)
*/
/*
String s1 = "123abc"; //常量池还没有,因此创建该字符串对象,并存入常量池
String s2 = "123abc"; //常量池中已经有了,直接重用对象
String s3 = "123abc"; //常量池中已经有了,直接重用对象
//引用类型==,比较地址是否相同
System.out.println(s1==s2); //true
System.out.println(s1==s3); //true
System.out.println(s2==s3); //true
•
s1 = s1+"!"; //创建新的字符串对象并将地址赋值给s1
System.out.println(s1==s2); //false,因为s1为新对象的地址,与s2不同了
*/
•
}
}
-
3.API基础和二进制
1.String常用方法、StringBuilder
1.String常用方法
1.string
package apiday01;
public class StringDemo {
public static void main(String[] args) {
//创建两个对象---一个字面量;另一个是在new String()时创建一个字符串对象
String s=new String("hello");
String s1="hello";
//==比较地址
System.out.println(s==s1);
//equals比较内容
System.out.println(s.equals(s1));
}
}
2.String常用方法(实例方法)
-
length()
package apiday01;
public class LengthDemo {
public static void main(String[] args) {
String str="你好中国123";
int len=str.length();
System.out.println(len);
}
} -
toUpperCase()--转大写,toLowerCase()--转小写
package apiday01;
/*
* toUpperCase()转大写
* toLowerCase()转小写
* */
public class ToUpperCaseDemo {
public static void main(String[] args) {
String str ="java";
str=str.toUpperCase();
System.out.println(str);
}
}
-
trim--去除当前字符串两边的空白字符
package apiday01;
/*String trim()
* 去除当前字符串两边的空白字符
* */
public class TrimDemo {
public static void main(String[] args) {
String str=" hello word ";
str=str.trim();
System.out.println(str);
}
}
-
boolean startsWith(String str)---判断当前字符串是否是以给定的字符串开始的
boolean endsWith()----判断当前字符串是否是以给定的字符串结束的
package apiday01;
/*
boolean startsWith --判断当前字符串是否是以给定的字符串开始的
boolean endsWith --判断当前字符串是否是以给定的字符串结束的
* */
public class StartsWithDemo {
public static void main(String[] args) {
String str="hello word";
boolean a=str.startsWith("hell");
boolean b=str.endsWith("word");
System.out.println(a);
System.out.println(b);
}
}
-
char charAt(int index)---返回当前字符串指定位置上的字符串---根据位置找字符
package apiday01;
/*char charAt(int index)
返回当前字符串指定位置上的字符串---根据位置找字符
* */
public class CharAtDemo {
public static void main(String[] args) {
String str="thinking in java";
char c=str.charAt(10);
System.out.println(c);
}
}
-
indexOf(String str) 检索字符在字符串中第一次出现的位置
package apiday01;
/*indexOf(String str) 检索字符在字符串中第一次出现的位置
* */
public class IndexOfDemo {
public static void main(String[] args) {
String str = "thinking in java";
int index = str.indexOf("in");//检索in在字符串str中第一次出现的位置
System.out.println(index);//2
index=str.indexOf("in",3);//从下标为3的位置开始找in的第一次
System.out.println(index);//5
index=str.indexOf("IN");//当前字符串不包含IN,所以返回-1
System.out.println(index);//-1
index=str.lastIndexOf("in");//in最后一次出现的位置
System.out.println(index);//9
}} -
substring
package apiday01;
/*
* substring(int a.int b)从字符串中截取从下标a开始,到下标b(不包含b)的内容
* */
public class SubstringDemo {
public static void main(String[] args) {
String str="www.tedu.cn";
String name=str.substring(3,7);//从第3位开始截取到7范围的字符串
System.out.println(name);//.ted
name =str.substring(5);//从第5位开始截取直到末尾
System.out.println(name);//edu.cn
}
}
5.getName()
public static void main (String[] args){
String name1="www.overwatch.com";
String name2="www.apex.com";
String name3="www.you.com";
String str1=getName(name1);
String str2=getName(name2);
String str3=getName(name3);
System.out.println(str1);
}
public String getName(String line){
int start =line.indexOf(".")+1;
int end=line.indexOf(".",start);
return line.substring(start,end);
}
3.String常用方法(静态方法)
-
static String.valueOf(数据类型a)
package apiday01;
/*
* String.valueOf(),将其他类型变量转换为String类型
* */
public class ValueOfDemo {
public static void main(String[] args) {
int a=123;
String s1=String.valueOf(a);//将int类型变量a转换为String类型并赋值给s1
System.out.println(s1);
double d=123.2434;
String s2=String.valueOf(d);//将double类型变量d转换为String类型并赋值给s2
System.out.println(s2);
String s3=a+"";//任何内容和字符串连接的结果都是字符串(效率低)
System.out.println(s3);
}
}
2.StringBuilder
-
由于String是不变对象,每次修改内容要创建新对象,因此String不适合做频繁修改操作,Java提供了StringBuilder类
-
StringBuilder是专门用于修改字符串的一个API,内部维护一个可变的char数组,修改都是在这个数组上进行的,修改速度、性能优秀,并且提供了修改字符串的常见方法:增、删、改、插
package apiday01;
public class StringBuilderDemo {
public static void main(String[] args) {
String str = "好好学习";
//复制str的内容
StringBuilder abc = new StringBuilder(str);
System.out.println(abc);//好好学习
//append()追加内容
abc.append(",为了找份好工作");
System.out.println(abc);//好好学习,为了找份好工作
//replace()替换内容
abc.replace(5, 10, "加油加油");
System.out.println(abc);//好好学习,加油加油工作
//delete()删除内容
abc.delete(0,5);
System.out.println(abc);//加油加油工作
//insert()插入内容
abc.insert(0,"守望先锋");
System.out.println(abc);//守望先锋加油加油工作
//reverse()翻转
abc.reverse();
System.out.println(abc);//作工油加油加锋先望守
}
}
3.getter()\setter()
//point类
public class point{
private int x;
private int y;
public int getX(){
this.x=x;
}
public void setX(){
return x;
}
public int getY(){
this.y=y;
}
public void setY(){
return y;
}
}
//SetterGetter类中的main中
Point a=new Point();
a.setX(100,200);
a.setY(629091);
System.out.println(a.getX()+a.getY());
2.正则表达式、Object、包装类
1.正则表达式
-
正则表达式是用来描述字符串内容格式,使用它通常用来匹配一个字符串的内容是否符合要求
-
正则表达式的语法:
[]:表示一个字符,该字符可以是[]中指定的内容
例如:
[abc]:这个字符可以是a或b或c
[a-z]:表示任意一个小写字母
[a-zA-Z]:表示任意一个字母
[a-zA-Z0-9_]:表示任意一个数字字母下划线
[^abc]:该字符只要不是a或b或c
•
预定义字符:
.:表示任意一个字符,没有范围限制
\d:表示任意一个数字,等同于[0-9]
\w:表示任意一个单词字符,等同于[a-zA-Z0-9_]
\s:表示任意一个空白字符
\D:表示不是数字
\W:不是单词字符
\S:不是空白字符
•
量词:
?:表示前面的内容出现0-1次
例如: [abc]? 可以匹配:a 或 b 或 c 或什么也不写
+:表示前面的内容最少出现1次
例如: [abc]+ 可以匹配:b或aaaaaaaaaa...或abcabcbabcbabcbabcbabbabab....
但是不能匹配:什么都不写 或 abcfdfsbbaqbb34bbwer...
*:表示前面的内容出现任意次(0-多次)---匹配内容与+一致,只是可以一次都不写
例如: [abc]* 可以匹配:b或aaaaaaaaaa...或abcabcbabcbabcbabcbabbabab....或什么也不写
但是不能匹配:abcfdfsbbaqbb34bbwer...
{n}:表示前面的内容出现n次
例如: [abc]{3} 可以匹配:aaa 或 bbb 或 aab 或abc 或bbc
但是不能匹配: aaaa 或 aad
{n,m}:表示前面的内容出现最少n次最多m次
例如: [abc]{3,5} 可以匹配:aaa 或 abcab 或者 abcc
但是不能匹配:aaaaaa 或 aabbd
{n,}:表示前面的内容出现n次以上(含n次)
例如: [abc]{3,} 可以匹配:aaa 或 aaaaa.... 或 abcbabbcbabcbabcba....
但是不能匹配:aa 或 abbdaw...
()用于分组,是将括号内的内容看做是一个整体
例如: (abc){3} 表示abc整体出现3次. 可以匹配abcabcabc
但是不能匹配aaa 或abcabc
(abc|def){3}表示abc或def整体出现3次.
可以匹配: abcabcabc 或 defdefdef 或 abcdefabc
但是不能匹配abcdef 或abcdfbdef
•
-
String支持与正则表达式相关的方法:
-
matches():使用给定的正则表达式验证当前字符串的格式是否符合要求
package apiday02;
/*邮箱的正确表达式
[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+
* */
public class MatchesDemo {
public static void main(String[] args) {
String email = "936572339@qq.com";
String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";
boolean match = email.matches(regex);
if (match) {
System.out.println("是正确的邮箱");
} else {
System.out.println("不是正确的邮箱");
}
}
} -
split():将当前字符串按照满足正则表达式的部分进行拆分
package apiday02;
•
import java.util.Arrays;
•
public class SplitDemo {
public static void main(String[] args) {
String line="abc123def456ghi";
String[] data=line.split("[0-9]+");
System.out.println(Arrays.toString(data));//[abc, def, ghi]
•
•
line="123.456.7898";
data=line.split("\\.");
System.out.println(Arrays.toString(data));//[123, 456, 7898]
•
•
line="123,456,789";
data=line.split(",");
System.out.println(Arrays.toString(data));//[123, 456, 789]
•
//最开始就是可拆分项(.),那么数组中的第一个元素为空字符串;
//如果连续两个(两个以上)可拆分项,他们中间也会被拆出一个空字符串;
//如果末尾连续多个可拆分项,那么拆出的空字符串被忽略
line=".123.456..789.11.11111.......";
data=line.split("\\.");
System.out.println(Arrays.toString(data));//[, 123, 456, , 789, 11, 11111]
•
•
•
}
}
• -
replaceAll():将当前字符串中满足正则表达式的部分替换为给定的字符串
package apiday02;
•
public class ReplaceAllDemo {
public static void main(String[] args) {
String line="abc123sss345ewww";
line=line.replaceAll("[a-z]+","xiaoyezi");
System.out.println(line);//xiaoyezi123xiaoyezi345xiaoyezi
}
}
•
-
2.Object
-
是所有类的鼻祖,所有类都直接或间接继承了Object,万物皆对象,为了多态
-
里面有几个经常被派生类重写的方法: toString()和equals()
-
调用toString()时默认返回: 类的全称@地址,没有参考意义,所以常常重写toString()返回具体数据
-
调用equals()时默认比较的还是==(即比较地址),没有参考意义,所以常常重写equals()来比较具体的属性值
-
派生类重写equals()的基本规则:
-
两个对象必须是同一类型,若类型不同则返回false
-
若参数对象为null,则返回false
-
原则上两个对象要比较对象的属性是否相同
-
-
3.包装类
-
Java定义了8个包装类,目的是为了解决基本类型不能直接参与面向对象开发的问题,使得基本类型可以通过包装类的实例以对象的方式存在
-
包括:Integer、Character、Byte、Short、Long、Float、Double、Boolean。其中Character和Boolean是直接继承自Object的,而其余6个包装类都继承自java.lang.Number
-
JDK1.5推出了一个新的特性:自动拆装箱,该特性是编译器认可,当编译器编译时若发现有基本类型与包装类型相互赋值时,将会自动补充代码来完成他们的转换工作,这个过程为自动拆装箱
-
package apiday02;
•
public class IntegerDemo {
public static void main(String[] args) {
//2)包装类可以将字符串转换为对应的基本类型---前提是该字符串正确表达了基本类型的值;若不能正确表达,则发生NumberFormatException数字转换异常
String str="123";
int num=Integer.parseInt(str);
System.out.println(num);//123
String str1="123.456";
double num1=Double.parseDouble(str1);
System.out.println(num1);//123.456
•
•
•
//1)可以通过包装类来得到基本类型的取值范围:
int max=Integer.MAX_VALUE;
int min =Integer.MIN_VALUE;
System.out.println("int的最大值为:"+max+",int的最小值为:"+min);
•
long lMax=Long.MAX_VALUE;
long lMin=Long.MIN_VALUE;
System.out.println("long的最大值为:"+lMax+",long的最小值为:"+lMin);
/** //自动拆装箱
//下列代码会被编译为:Integer i1=Integer.valueOf(5)
Integer i1=5;
//int i2=i1.int.valueOf()
int i2=i1;
System.out.println(i1+","+i2);*/
}
}
4.二进制
1.2进制
-
逢二进一的计数规则
-
如何将2进制转换为10进制?
-
将一个2进制数每个1位置的权值累加即可
-
-
Java 所有的变量\常量存储的都是2进制数
-
代码
public class Demo01 {
public static void main(String[] args) {
/*
1.java在编译期间将10进制数编译为2进制数,按2进制来运算
.java(50) 编译后 .class(110010)
2.Integer.toBinaryString()可以将底层的2进制数显示出来
3.int类型是32位2进制数,显示2进制数时自动省略高位0
4.System.out.println()将2进制转换为10进制输出
*/
int n = 50; //110010
System.out.println(Integer.toBinaryString(n)); //2进制
n++; //110011
System.out.println(n); //10进制
System.out.println(Integer.toBinaryString(n)); //2进制
}
}
•
2.16进制
-
逢16进1的计数规则
-
16进制来缩写2进制数字
-
缩写: 将2进制从最低位开始,每4位2进制缩写为1位16进制
-
public class Demo02 {
public static void main(String[] args) {
/*
16进制:缩写2进制
1)0x是16进制字面量前缀,0x开头则编译器按照16进制编译
2)Java 7提供了2进制字面量前缀 0b----不用,一般都用16进制
*/
int n = 0x4f057afe; //0x表示16进制
int m = 0b1001111000001010111101011111110; //0b表示二进制
System.out.println(Integer.toBinaryString(n)); //按2进制输出
System.out.println(Integer.toBinaryString(m)); //按2进制输出
//结论:用16进制来表示2进制更方便
•
/*
8进制:
1)逢8进1的计数规则
2)前缀0表示为8进制
3)数字:0,1,2,3,4,5,6,7,没有7以上的数字
*/
//----小面试题(8进制平时不用)
//权 64 8 1
int x = 067; //0开头表示8进制
System.out.println(x); //十进制的55(6个8加上7个1)
•
}
}
•
3.补码
-
计算机中处理有符号数(正负数)的一种编码方式,java中的补码最小类型是int,32位数
-
以4位2进制为例讲解补码的编码规则:
-
计算的时候如果超出4位数就自动溢出舍弃,保持4位数不变
-
将4位2进制数分一半作为负数使用
-
int n = -3;
System.out.println(Integer.toBinaryString(n));
•
/*
规律数:
1)0111为4位补码的最大值,规律是1个0和3个1,可以推导出:
32位补码的最大值,是1个0和31个1-----(011111111...)
2)1000为4位补码的最小值,规律是1个1和3个0,可以推导出:
32位补码的最小值,是1个1和31个0-----(100000000...)
3)1111为4位补码的-1,规律是4个1,可以推导出:
32位补码的-1是,是32个1------------(11111111...)
*/
int max = 2147483647; //int的最大值
int min = -2147483648; //int的最小值
System.out.println(Integer.toBinaryString(max)); //011111...
System.out.println(Integer.toBinaryString(min)); //100000...
System.out.println(Integer.toBinaryString(-1)); //11111...
•
•
-
-
深入理解负值:
-
记住-1的编码是32个1
-
用-1减去0位置对应的权值
-
-
互补对称:
-
公式:-n=~n+1 结论:一个数的补码=这个数取反+1
-
代码
int n = -3;int m = ~n+1;System.out.println(m); //3 -3的补码就是-3取
-
-
位运算:
-
~:取反(0变1、1变0)
-
&:与运算(有0则0)
-
|:或运算(有1则1)
-
“>>>”:右移位运算
-
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理