Java学习
一、java版本
JavaSE :标准版(桌面应用程序、控制台程序)
JavaEE:E企业级开发(Web端,服务器的开发)
JDK:Java开发工具
JRE:Java运行环境
JVM:跨平台特性的主要实现方式,Java虚拟环境
二、运行机制
编译型:一次性编译
解释型:边解释边运行
三、数据类型
- 基本数据类型,基本引用类型:类、接口、数组
- 基本数据类型:数值值是存在自己的空间中的
- 引用数据类型:数据值存储在其他的空间中的,自己的空间存储的是地址值。
- 基本数据类型进行的是数值传递,引用数据类型进行的地址传递。
int[] array={1,2,3};`
`int array1=array;
public class test1 {
public static void main(String[] args) {
int i=10;
int i2=010;//八进制
int i3=0x10;//十六进制
System.out.println(i);
System.out.println(i2);
float f=0.1f;
double d=1.0/10;
System.out.println(f==d);//false
//银行大型数据的比较要使用BigDecimal类,慎用float数据类型
}
}
1.bool型的默认值为false;
2.string类型的默认值为NUll;
3.int型的默认值为0;
4.final定义常量;
四、数组
4.1 数组
//对数组进行乱序排列,堆存储对象或者数组,使用new进行创建
public class test8_array03 {
public static void main(String[] args) {
Random r=new Random();
int[] array={1,2,3,4,6};
int temp;
for (int i = 0; i < array.length; i++) {
int index=r.nextInt(array.length);
temp=array[index];
array[index]=array[i];
array[i]=temp;
}
for (int i = 0; i < array.length; i++) {
System.out.print("\t"+array[i]);
}
}
}
4.2 Java内存
1.数组array[]的数组的地址存储在栈中,而数组的数值存储在堆中。
2.main()方法也存在栈内存中。
3.只要是new出来的一定是在堆里面开辟了一个小空间。
4.如果new了很多次,那么在堆里面一定是有很多个小空间,每个小空间都有各自的数据。
//两个数组共享一个数组的首地址
public static void main(String[] args) {
int[] array1={11,22};
int[] array2=array1;
System.out.println(array1);
System.out.println(array2);
}
4.3 二维数组
package Basement;
/**
* @Author: Guojiang
* @Date: 2022/12/29/14:46
* @Description:
*/
/*
二维数组的静态初始化:
数据类型[][] 数组名=new 数据类型[][]{{元素1,元素2,元素3},{元素1,元素2,元素3}};
简化格式:
数据类型[][] 数组名={{元素1,元素2,元素3},{元素1,元素2,元素3}};
元素访问:
数组名[索引][索引];
二维数组的遍历:
先得到一维数组,再遍历一维数组获取元素;
*/
public class test5_method_08 {
public static void main(String[] args) {
int[][] arr=new int[][]{{11,22},{23,24,999,25}};
for (int i = 0; i < arr.length; i++) {
for (int j=0;j< arr[i].length;j++)
{
System.out.println(""+arr[i][j]);
}
}
}
}
package Basement;
/**
* @Author: Guojiang
* @Date: 2022/12/29/16:10
* @Description:
*/
public class test5_method_09 {
public static void main(String[] args) {
int[][] yearArr={
{22, 44, 66},
{77, 33, 88},
{25, 45, 65},
{11, 66, 99}
};
//全年的业务总和
int yearSum=0;
for (int i = 0; i < yearArr.length; i++) {
int[] quarterArr=yearArr[i];
int sum=Sum(quarterArr);
System.out.println("第"+(i+1)+"季度"+sum);
yearSum+=sum;
}
System.out.println("全年的营业额为"+yearSum);
}
//就算每一个季度的营业额
public static int Sum(int[] array){
int sum=0;
for (int i = 0; i < array.length; i++) {
sum+=array[i];
}
return sum;
}
}
五、方法
5.1 方法的重载
1.在同一个类中,定义了多个重名的方法,这些同名的方法具有同种的功能。
2.每个方法不同的参数类型或参数个数,这些同名的方法就构成了重载关系。
3.java通过参数区分重载关系中的不同方法。
public class test_5_method01 {
public static int Sum_a_b(int a,int b)
{
return a+b;
}
public static int Sum_a_b(int a,int b,int c)
{
return a+b+c;
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入数字a");
int a=sc.nextInt();
System.out.println("请输入数字b");
int b=sc.nextInt();
System.out.println("请输入数字b");
int c=sc.nextInt();
//对a和b求和
System.out.println("a+b的结果是\t"+Sum_a_b(a,b));
System.out.println("a+b+c的结果是\t"+Sum_a_b(a,b,c));
}
}
package Basement;
public class test5_method_02 {
public static void main(String[] args) {
/*使用重载的方式比较两个整数是否相同
*/ compare((int)10,(int)20);
}
public static void compare(short b1,short b2)
{
System.out.println("short");
System.out.println(b1==b2);
}
public static void compare(byte b1,byte b2)
{
System.out.println("byte");
System.out.println(b1==b2);
}
public static void compare(int b1,int b2)
{
System.out.println("int");
System.out.println(b1==b2);
}
public static void compare(long b1,long b2)
{
System.out.println("long");
System.out.println(b1==b2);
}
}
六、面向对象
6.1 类
1.如何定义一个类?
public class Phone {
//属性(成员变量)
//行为(方法)
public void call() {
}
}
2.如何得到类的对象?
类名 对象名=new 类名();
Phone phone=new Phone();
3.定义类的补充注意事项
用来描述一类事物的类,专业叫做:Javabean类,在Javabean类中是不写main方法的。
之前编写main方法的类,叫做测试类。
6.2 封装
1.什么是封装?
对象代表的是什么,就得封装对应的数据,并提供数据对应的行为,例如:人关门,关门这个行为应该封装在”门“这个对象的行为中。
2.private关键字
权限修饰符,可以修饰成员(成员变量和成员方法),被private修饰的成员只能在本类中才能被访问。
6.3.就近原则和this关键字
System.out.println(age);//寻找就近的age
System.out.println(this.age);//寻找成员变量的age:
this关键字可以区分成员变量和局部变量
6.4 构造方法
1.构造方法的作用?
创建对象的时候,由虚拟机自动调用,给成员变量进行初始化的。
2.构造方法的种类?
无参构造方法:初始化对象时,成员变量的数据均采用默认值。
有参构造方法:在初始化对象时,同时可以为对象进行赋值。
3.构造方法注意事项
任何类定义出来,默认自带无参数构造器,写不写都有。
一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写无参数构造器。
建议在任何时候都要手动写上空参和带全部参数的构造方法。
4.构造方法概述
创建对象时,虚拟机会自动调用构造方法,作用是给成员变量进行初始化的。
6.5 标准的Javabean类
1.标准的JavaBean类
类名需要见名知意;成员变量需要使用private修饰;提供至少两个构造方法;成员方法:提供每一个成员变量对应的Set()和get()方法。
生成构造方法的快捷键:alt+insert,alt+fn+insert,ptg插件。
6.6 Java内存分配介绍
1.对象的内存分配图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6HW0ASnN-1675244616287)(C:\Users\18508\Desktop\java学习\笔记\image-20221230104356421.png)]
2.this的内存原理图
this的本质:代表方法调用者的地址值。
6.7 对象实例联系
1.文字格斗游戏
//补充的%s
public class test10 {
/* 两部分参数:
第一部分参数:要输出的内容%s(占位)
第二部分参数:填充的数据*/
public static void main(String[] args) {
System.out.printf("%s你好啊张三%s","你好","我也好");
}
}
package Subject.test5;
import java.util.Random;
/**
* @Author: Guojiang
* @Date: 2022/12/30/12:12
* @Description:
*/
public class Role {
private String name;
private int blood;
public Role() {
}
public Role(String name, int blood) {
this.name = name;
this.blood = blood;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return blood
*/
public int getBlood() {
return blood;
}
/**
* 设置
* @param blood
*/
public void setBlood(int blood) {
this.blood = blood;
}
public void attack(Role role)
{
//计算造成的伤害
Random r=new Random();
int hurt=r.nextInt(20)+1;
int remindBlood=role.getBlood()-hurt;
//对血量进行验证,如果为负数则等于0;
remindBlood=remindBlood>0? remindBlood:0;
//重新设置角色的血量
role.setBlood(remindBlood);
//this表示方法的调用者
System.out.println(this.getName()+"举起拳头,打了"+role.getName()+"一下,"+"造成了"+hurt+"点伤害,"+role.getName()+"还剩下了"+role.getBlood()+"点血");
}
}
package Subject.test5;
/**
* @Author: Guojiang
* @Date: 2022/12/30/12:22
* @Description:
*/
public class RoleTest {
public static void main(String[] args) {
Role role1=new Role("乔峰",100);
Role role2=new Role("鸠摩智",100);
while(true)
{
role1.attack(role2);//乔峰攻击了鸠摩智
//如果鸠摩智的血量为0,则跳出循环
if(role2.getBlood()==0)
{ System.out.println(role2.getName()+"已经被打死");
break;
}
}
while(true)
{
role2.attack(role1);//乔峰攻击了鸠摩智
//如果鸠摩智的血量为0,则跳出循环
if(role1.getBlood()==0) {
System.out.println(role1.getName() + "已经被打死");
break;
}
}
}
}
6.8 API和API的帮助文档
七、字符串
7.1 String概述
1.String是一个定义好的类,定义在Java.lang包中,所以使用的时候不用导包。
2.java程序中的所有字符串文字(例如“发哈时间发货”)都被实为此类的对象。
3.字符串不可变,他们的值在创建后不可改变。
7.2 创建String对象
package Basement;
/**
* @Author: Guojiang
* @Date: 2023/01/06/14:48
* @Description:
*/
public class test12 {
public static void main(String[] args) {
//采用直接赋值的方法,获取一个字符串对象
String name="abcd";
System.out.println(name);
//使用new的方法获取一个字符串对象
//空参构造:可以获取一个空白的字符串对象
String s2=new String();
System.out.println("@"+s2+"!");
//传递一个字符串,根据字符串内容再创建一个新的字符串对象
String s3=new String("abcd");
System.out.println(s3);
//传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
char[] chars={'a','b','c','d'};
String s4=new String(chars);
System.out.println(s4);
//传递一个字节数组,根据字节数组在创建一个新的字符串对象
byte[] bytes={97,98,99,100};
String s5=new String(bytes);
System.out.println(s5);
}
}
注意:
当使用双引号进行赋值时,系统会检查该字符串在串池中是否存在。不存在的时候,创建新的;存在,进行复用。
7.3 字符串的比较
1.基本数据类型比较的是:数值;基本引用类型比较的是:地址值;
package String;
import java.util.Scanner;
/**
* @Author: Guojiang
* @Date: 2023/01/06/17:02
* @Description:
*/
public class test1 {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "ab";
System.out.println(str1 == str2);
//如果两个字符串的地址相同,则字符串指向同一个地址;若不相同,指向不同的地址,则为False
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2);//new的地址不相同,所以比较结果为False
//3.比较字符串对象中的内容是否相等
boolean result = str1.equals(str2);
System.out.println(result);
//4.比较字符串对象中的内容是否相等,忽略大小
boolean result1 = s1.equalsIgnoreCase(s2);
System.out.println(result1);
Scanner scanner=new Scanner(System.in);
System.out.println("请输入一个字符串");
String string=scanner.next();//这是输入的是new一个对象,所以单纯的字符串比较并不可以相同
boolean re=string.equals(s2);
System.out.println(re);
}
}
2.实现简单的登录
package String;
import java.util.Scanner;
/**
* @Author: Guojiang
* @Date: 2023/01/06/21:27
* @Description:
*/
public class test {
public static void main(String[] args) {
String userBName="abc";
String password="123456";
Scanner scanner=new Scanner(System.in);
for (int i = 0; i < 3; i++) {
System.out.println("请输入账号");
String user=scanner.next();
System.out.println("请输入密码");
String pass=scanner.next();
if(user.equals(userBName)&&pass.equals(password))
{
System.out.println("登录成功");
break;
}
else{
if(i==2){
System.out.println("账号已经被锁定,联系客服");
}
else System.out.println("账号或密码错误!请重新输入,您还有"+(2-i)+"次机会");
}
}
}
}
7.4 遍历字符串
package String;
import java.util.Scanner;
/**
* @Author: Guojiang
* @Date: 2023/01/06/21:41
* @Description:
*/
public class test2 {
public static void main(String[] args) {
//键盘输入一个字符串
Scanner scanner=new Scanner(System.in);
System.out.println("请输入一个字符串");
String str=scanner.next();
//进行遍历
int Big=0;
int small=0;
int number=0;
for (int i = 0; i < str.length(); i++) {
//i表示字符串的每一个索引
char c=str.charAt(i);
//if(c>=65&&c<=90)
if(c>='a'&&c<='z')
Big++;
else if(c>=48&&c<=57)
number++;
else
small++;
}
System.out.println("字符串的长度为"+str.length());
System.out.println("大写字母的个数为"+Big);
System.out.println("数字的个数为"+number);
System.out.println("小写字母的个数为"+small);
}
}
7.5 StringBuilder
1.StringBuilder可以看作是一个容器,创建之后里面的内容那个是可以变化的。作用:提高了字符串的操作效率。
2.StringBuilder一般用作字符的反转,拼接。但是StringBuilder的对象是一个容器,使用后要使用to.String()转化为String类型
public class test10 {
public static void main(String[] args) {
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(123).append(123);
System.out.println(stringBuilder);//这时候输出的stringBuilder并不是字符串类型,所以要更改为字符串类型
String str=stringBuilder.toString();
System.out.println(str);
}
}
package String;
import java.util.Scanner;
/**
* @Author: Guojiang
* @Date: 2023/01/08/17:56
* @Description:
*/
public class test10 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入一个字符串");
String str=scanner.next();
//反转输入的字符串
/* StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(str);
stringBuilder.reverse();
String newStr=stringBuilder.toString();*/
String newStr= new StringBuilder().append(str).reverse().toString();
if(str.equals(newStr))
{
System.out.println("字符串是对称的");
}
else
{
System.out.println("该字符串非对称");
}
}
}
7.6 StringJoiner
1.JDK8出现的一个可变的操作字符串的容器,可以高效的,方便的拼接字符串。在拼接的时候,可以指定间隔符号,开始符号和结束符号。
-
-
Modifier and Type Method and Description StringJoiner
add(CharSequence newElement)
将给定的副本CharSequence
值作为下一个元素StringJoiner
值。int
length()
返回此StringJoiner
的String
表示的长度。StringJoiner
merge(StringJoiner other)
添加给定的StringJoiner
的内容,没有前缀和后缀作为下一个元素,如果它是非空的。StringJoiner
setEmptyValue(CharSequence emptyValue)
设置序列的字符时要使用确定的字符串表示的这个StringJoiner
,而没有单元已被添加然而,就是当它是空的。String
toString()
返回当前值,由的prefix
,值添加由迄今分离delimiter
和suffix
,除非没有元素已经在这种情况下,被添加prefix + suffix
或emptyValue
被返回的字符
-
7.4 字符串原理
1.字符串存储的原理:直接赋值会复用字符串常量池中的;new出来不会复用,而是开辟一个新空间。
2.“==”比较的是什么?基本数据类型比较的是数值;基本引用类型比较的是地址值。
3.字符串拼接的底层原理?
如果没有变量参与,都是字符串直接相加,编译之后就是拼接的结果,会复用串池中的字符串。
4.StringBuilder的底层原理
所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存。
5.StringBuilder的源码分析?
默认创建一个长度为16的字节数组;添加的内容长度小于16,直接存储;若添加的北荣大于16还会扩容(原来容量的*2+2);弱国扩容之后还不够,则以实际长度为准。
7.5 字符串练习
7.5.1字符串旋转校验
package String;
/**
* @Author: Guojiang
* @Date: 2023/01/10/16:55
* @Description:
*/
public class test14 {
public static void main(String[] args) {
String strA="abcde";
/*String strB="cdeab";*/
String strB="bcdea";
boolean result=checkString(strA,strB);
System.out.println(result);
}
//对旋转后的字符串进行校验
public static boolean checkString(String strA,String strB)
{
for (int i = 0; i < strA.length(); i++) {
strA=rotate(strA);
if(strA.equals(strB))
{
return true;
}
}
return false;
}
//方法一:采用SubString()对字符串进行截取之后旋转
public static String rotate(String str)
{
char first=str.charAt(0);//截取首字符
String end=str.substring(1);//截取首字符以外的字符
return end+first;
}
//方法二:将字符串转化为字符型数组,然后岁数组操作,进行对字符串进行旋转
/*public static String rotate(String str)
{
char[] arr=str.toCharArray();
//拿到0索引上的字符
char first=arr[0];
for (int i = 1; i < arr.length; i++) {
arr[i-1]=arr[i];
}
arr[arr.length-1]=first;
//利用数组创建一个字符串对象
String result=new String(arr);
return result;
}*/
}
7.5.2.数字字符串相乘
提示:数字转化为字符串的方法
方法一:直接强制转换。如:String str= (String)123;
方法二:直接通过空字符串+数字的形式转换为字符串(前后都可以用)。如:String str= “”+123;
方法三:直接通过包装类来实现。如:String str = String.valueOf(1231);
package String;
/**
* @Author: Guojiang
* @Date: 2023/01/11/12:06
* @Description:将两个定义的字符串类型的数字串相乘,乘积以字符串的类型返回
*/
public class test16 {
public static void main(String[] args) {
String num1="12345";
String num2="123456";
String string=MulString(num1,num2);
System.out.println("字符串相乘后的结果字符串为:"+string);
}
//字符串类型相乘,并返回字符串
public static String MulString(String num1,String num2)
{
int number1=0,number2=0,mul=0;
//字符串转化为数字的核心方法
for (int i = 0; i < num1.length(); i++) {
int c= (num1.charAt(i)-48);
number1=c+number1*10;
}
for (int i = 0; i < num2.length(); i++) {
int c= (num2.charAt(i)-48);
number2=c+number2*10;
}
mul=number1*number2;
/*方法一:直接强制转换。如:String str= (String)123;
方法二:直接通过空字符串+数字的形式转换为字符串(前后都可以用)。如:String str= ""+123;
方法三:直接通过包装类来实现。如:String str = String.valueOf(1231);*/
String string=""+mul;
// String string=String.valueOf(mul);
return string;
}
}
八、ArrayList
8.1 集合的基本使用
8.1.1集合和数组的对比
1.长度和存储类型
(1)长度:数组的长度固定,集合的长度可变。
(2)存储类型:数组可以存基本数据类型和引用数据类型;集合可以存放引用数据类型和基本数据类型(必须包装类)。
8.2 基本操作
-
-
boolean
add(E e)
将指定的元素追加到此列表的末尾。void
add(int index, E element)
在此列表中的指定位置插入指定的元素。boolean
addAll(Collection<? extends E> c)
按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。boolean
addAll(int index, Collection<? extends E> c)
将指定集合中的所有元素插入到此列表中,从指定的位置开始。void
clear()
从列表中删除所有元素。Object
clone()
返回此ArrayList
实例的浅拷贝。boolean
contains(Object o)
如果此列表包含指定的元素,则返回true
。void
ensureCapacity(int minCapacity)
如果需要,增加此ArrayList
实例的容量,以确保它可以至少保存最小容量参数指定的元素数。void
forEach(Consumer<? super E> action)
对Iterable
的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。E
get(int index)
返回此列表中指定位置的元素。int
indexOf(Object o)
返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。boolean
isEmpty()
如果此列表不包含元素,则返回true
。Iterator<E>
iterator()
以正确的顺序返回该列表中的元素的迭代器。int
lastIndexOf(Object o)
返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。ListIterator<E>
listIterator()
返回列表中的列表迭代器(按适当的顺序)。ListIterator<E>
listIterator(int index)
从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。E
remove(int index)
删除该列表中指定位置的元素。boolean
remove(Object o)
从列表中删除指定元素的第一个出现(如果存在)。boolean
removeAll(Collection<?> c)
从此列表中删除指定集合中包含的所有元素。boolean
removeIf(Predicate<? super E> filter)
删除满足给定谓词的此集合的所有元素。protected void
removeRange(int fromIndex, int toIndex)
从这个列表中删除所有索引在fromIndex
(含)和toIndex
之间的元素。void
replaceAll(UnaryOperator<E> operator)
将该列表的每个元素替换为将该运算符应用于该元素的结果。boolean
retainAll(Collection<?> c)
仅保留此列表中包含在指定集合中的元素。E
set(int index, E element)
用指定的元素替换此列表中指定位置的元素。int
size()
返回此列表中的元素数。void
sort(Comparator<? super E> c)
使用提供的Comparator
对此列表进行排序以比较元素。Spliterator<E>
spliterator()
在此列表中的元素上创建*late-binding和故障快速*Spliterator
。List<E>
subList(int fromIndex, int toIndex)
返回此列表中指定的fromIndex
(包括)和toIndex
之间的独占视图。Object[]
toArray()
以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。<T> T[]
toArray(T[] a)
以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。void
trimToSize()
修改这个ArrayList
实例的容量是列表的当前大小。
-
8.3 集合练习
package ArrayListTest;
/**
* @Author: Guojiang
* @Date: 2023/01/12/9:59
* @Description:手机的Javablei
*/
public class Phone {
private String brand;
private double price;
public Phone() {
}
public Phone(String brand, double price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
package ArrayListTest;
import java.util.ArrayList;
/**
* @Author: Guojiang
* @Date: 2023/01/12/10:03
* @Description:定义一个方法,返回低于3000元的手机信息
*/
public class PhoneTest {
public static void main(String[] args) {
//创建集合
ArrayList<Phone> arrayList=new ArrayList<>();
//声明对象
Phone phone1=new Phone("小米",1199.00);
Phone phone2=new Phone("苹果",8000.00);
Phone phone3=new Phone("苹果",8000.00);
//插入集合
arrayList.add(phone1);
arrayList.add(phone2);
arrayList.add(phone3);
//查询价格低于3000的手机信息
Phone phone=Select_less(arrayList);
if(phone==null)
{
System.out.println("不存在低于3000元以下的手机");
}
else
{
System.out.println(phone.getBrand());
}
}
public static Phone Select_less(ArrayList<Phone> arrayList)
{
for (int i = 0; i < arrayList.size(); i++) {
Phone phone=arrayList.get(i);
double money=phone.getPrice();
if(money<3000)
{
return phone;
}
}
return null;
}
}
九、面向对象进阶
9.1static-静态变量
1.static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量,被static修饰的成员变量,叫做静态变量;被static修饰的成员方法,称作静态方法,多用在测试类和工具类中;javaBean类很少使用。
2.静态变量特点:被该类所有对象共享,不属于对象,属于类。调用方式:类名调用(推荐),对象名调用。
3.静态变量是随着类的加载而加载的,优于对象存在的,静态变量存储在堆内存中。
4.javaBean类:用来描述一些事物的类,比如,Student,Teacher,Dog,Cat等。
5.测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口。
6.工具类:不是用来描述一类事物的,而是帮助我们做一些事情的类。
类名要见名知意,私有化构造方法。
7.私有构造的作用: 私有构造可以保证类不会被外部调用。如果想要创建此类的对象,只需在本类new自己的私有构造来创建一个对象,对外暴露此方法。
9.2static的注意事项
1.静态的变量只能访问静态的方法和静态的变量。
2.非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法。
3.静态方法中没有this关键字。
总结:静态方法中,只能访问静态;非静态方法可以访问所有;静态方法中没有this关键字;
9.3继承概述
1.什么是继承?
继承是面向对象的三大特征之一,可以让类跟类之间产生子父的关系。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
2.什么时候用继承?
当类与类之间,存在相同的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。
3.继承的格式?
public class 子类 extends 父类{ }
4.继承后子类的特点?
子类可以得到父类的属性和行为,子类可以使用;子类可以在父类的基础上增加新的功能,子类更加强大。
9.4继承的特点
9.4.1综述
1.Java只支持单继承,不支持多继承,但支持多层继承。
2.多层继承:子类A继承父类B,子类B继承父类C,子类C为子类A的间接父类,子类B为子类A的直接父类。
9.4.2子类继承内容
继承内容 | ||
---|---|---|
构造方法 | 非私有 不可继承 | 私有 不可继承 |
成员变量 | 非私有 可以继承 | 私有 可以继承(使用get(),set()) |
成员方法 | 虚方法 可以继承 | 否则 不可继承 |
1.如果一个类中没有构造方法,那么虚拟机会自动给你添加一个默认的空参构造方法。
2.成员方法继承采用虚方法表(非private,非static,非final),在最小子类的虚方法表上加上上层父类的虚方法。通过查询虚方法表确定方法在哪个父类中,进而进行快速定位。
9.4.3成员变量
1.成员变量访问特点代码
package extendsDemo.demo1;
/**
* @Author: Guojiang
* @Date: 2023/01/28/14:36
* @Description:成员变量继承测试
*/
public class Test {
public static void main(String[] args) {
Zi zi=new Zi();
zi.show();
}
}
//父类
class Fu
{
String name="Fu";
String hobby="喝奶茶";
}
class Zi extends Fu
{
String name="zi";
String game="吃鸡";
//就近原则打印
public void show(){
String name="张三";
//打印本类中的成员变量的信息
System.out.println(name);
//打印本类中成员信息
System.out.println(this.name);
//打印父类成员变量的信息
System.out.println(super.name);
//打印的信息都为喝奶茶
System.out.println(super.hobby);
System.out.println(this.hobby);
System.out.println(hobby);
//打印game
System.out.println(this.game);
System.out.println(game);
}
}
2.成员变量的访问总结
遵循就近原则:现在局部位置找,本类成员位置找,父类成员位置找,逐级往上找。
3.如果出现重复的成员变量怎么办?
System.out.println(name);//从局部位置往上找
System.out.println(this.name);//从本类成员位置往上找
System.out.println(super.name);//从父类成员位置网上找
9.4.4成员方法
1.调用原则
直接就近原则:谁离我近,就直接用谁。super调用直接访问父类。
2.方法重写
[1] 当父类的方法无法满足子类的现在的需求时,需要进行方法的重写。
[2] 书写格式:在继承体系中,子类出现了和父类一模一样的方法声明,我们称子类这个方法是重写的方法。
[3] @override重写注解:是放在重写后的方法上,检验子类重写时语法是否正确。
3.方法重写注意事项和要求
[1] 重写的方法的名称、形参列表必须与父类中的保持一致。
[2] 子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected<public)
[3] 子类重写父类方法时,返回值类型子类必须小于等于父类。
[4] 建议:重写的方法尽量和父类保持一致。
[5] 只有被添加到虚方法表中的方法才可以被重写。
注意事项 this调用:就近原则;super调用:直接找父类。
9.4.5构造方法
1.构造方法的访问特点
[1] 父类中的构造方法不会被子类继承。
[2] 子类中的所有构造方法默认先访问父类中的无参构造,再执行自己。
[3] 为什么?
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
子类在初始化之前,一定调用父类构造方法先完成父类数据空间的初始化。
[4] 怎么调用父类构造方法?
子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在第一行。
2.访问特点总结
[1] 子类不能继承父类的构造方法,但是可以通过super调用。
[2] 子类构造方法的第一行,有一个默认的super();
[3] 默认先访问父类中无参的构造,再执行自己。
[4] 如果想要方法文父类有参构造,必须手写书写。
9.4.6this和super关键字
1.this:理解为一个变量,表示当前方法调用者的地址值。
2.super:代表父类的存储空间。
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量;访问本类成员变量 | this.成员方法(…);访问本类成员方法 | this(…);访问本类构造方法 |
super | siper.成员变量;访问父类成员变量 | super.成员方法(…);访问父类成员方法 | super(…);访问父类构造方法 |
9.5多态
9.5.1概念
1.多态
指为不同数据类型的实体提供统一的接口,同类型对象的多种形态。
2.多态的前提
[1]有继承/实现关系
[2]有父类引用指向子类对象。
[3]有方法的重写
3.多态的好处
使用父类型作为参数,接收所有子类对象,体现多态的扩展性与便利。
9.5.2调用成员特点
1.调用成员变量的特点:编译看左边,运行也看左边;
调用成员方法的特点:编译看左边,运行看右边;
package polymorphism.demo2;
/**
* @Author: Guojiang
* @Date: 2023/01/29/10:32
* @Description:
*/
public class Test {
public static void main(String[] args) {
Animal animal=new Dog();
//调用成员变量的特点:编译看左边,运行也看左边
//先看父类的成员变量是否存在,不存在则编译失败
System.out.println(animal.name);
//调用成员方法的特点:编译看左边,运行看右边
//方法如果子类存在会覆盖掉原来父类的方法,进而调用层级,从本类依次往上
animal.show();
}
}
class Animal{
String name="动物";
public void show()
{
System.out.println("Dog---show方法");
}
}
class Dog extends Animal
{
String name="狗";
public void show()
{
System.out.println("Dog-----show方法");
}
}
9.5.3优势和弊端
1.多态的优势
方法中,使用父类型作为参数,可以接收所有子类对象。
2.多态的弊端
不能使用子类的特有功能
3.引用数据类型的类型转换,有几种方式?
自动类型转换,强制类型转换
4.强制类型转换能解决什么问题?
[1]可以转换成真正的子类类型,从而调用子类独有的功能。
[2]转换类型与真实对象类型不一致会报错。
9.6 包和final
9.6.1包
1.包的作用?
包就是文件夹,用来管理各种不同功能的Java类。
2.包名书写的规则?
公司域名反写+包的作用,需要全部英文小写,见名知意。
3.什么是全类名?
包名+类名
4.什么时候需要导包?什么时候不需要导包?
[1]使用同一个包中的类时,不需要导包。
[2]使用java.lang包中的类时,不需要导包。
[3]其他情况都需要导包。
[4]如果同时使用两个包中的同名类时,需要使用全类名。
9.6.2final
1.final修饰的方法:表明该方法是最终方法,不能被重写。
2.final修饰的类,表明是最终类,不能被继承。
3.final修饰的变量叫做常量,只能被赋值一次。
4.常量
[1]实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
[2]常量的命名规范
单个单词:全部大写;多个单词:全部大写,单词之间用下划线隔开。
5.final细节
[1]final修饰的变量是基本类型:那么存储的数据值不能发生改变。
[2]final修饰的变量是引用类型,那么变量存储的地址值不能发生改变,对象内部的可以改变。
9.7权限修饰符和代码块
9.7.1权限修饰符
1.权限修饰符的分类
作用范围:private<默认(空着不写)<protected<public
修饰符 | 同一个类中 | 同一个包中的其他类 | 不同包下的子类 | 不同包下的无关类 |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
2.使用规则
[1]实际开发中,一般只用private和public.
[2]成员变量私有,方法公开。
特例:如果方法中的代码是抽取其他方法中的共性代码,这个方法一般也私有。
9.7.2代码块
1.代码块的分类
局部代码块,构造代码块,静态代码块
2.局部代码块的作用?
提前结束变量的声明周期(已淘汰)。
3.构造代码块的作用?
抽取构造方法中的重复代码(不够灵活),可以通过定义方法调用解决重复代码。
4.静态代码块的作用?
数据的初始化。
9.8 抽象类和抽象方法
1.抽象类概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
2.抽象方法概念
如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
3.抽象类和抽象方法注意事项
[1]抽象类不能实例化(不能创建对象)
[2]抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
[3]可以有构造方法
[4]抽象类的子类
要么重写抽象类中的所有抽象方法(常用),要么是抽象方法。
4.抽象类是怎么样的?
[1]抽取共性时,无法确定方法体,就把方法定义为抽象的。
[2]强制让子类按照某种格式重写。
[3]抽象方法所在的类,必须是抽象类。
5.抽象类和抽象方法的格式?
`public abstract 返回值类型 方法名(参数列表)`
`public abstract class 类名{}`