java基础知识-小记

java基础-复习随笔小记

重载

方法重载
1.指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返
回值类型无关。
2.参数列表:个数不同,数据类型不同,顺序不同。
3.重载方法调用:JVM通过方法的参数列表,调用不同的方法。

内存

变量的内存分布注意:成员变量存放在内存的堆中;局部变量存放在内存的栈中。

举例:对象内存图
如下:一个对象,调用一个方法内存图
一个对象调用一个方法内存图

如下是:两个对象调用同一方法内存图
两个对象调用同一方法内存图

如下图:一个引用,作为参数传递到方法中内存图一个引用,作为参数传递到方法中内存图
对于数组而言
数组相关的内存分布举例

Scanner类、Random类

System.in 系统输入,指的是通过键盘录入数据
Scanner类是一个可以解析基本类型和字符串的简单文本扫描器

Scanner sc = new Scanner(System.in);
int i = sc.nextInt();//接收一个键盘录入的整数

Random类:生成随机数
public int nextInt(n):生成一个0(包括)到n(不包括)之间的值

Random r = new Random();
int i = r.nextInt(10);

ArrayList

ArrayList不能存储基本数据类型,只能存储引用数据类型。所以类似不能写。但是存储基本类型对应的包装类型是可以的。所以要想存储基本数据类型,需要先将数据类型转换为对应的包装类型才可以。转换图如下:基本数据类型与包装数据类型的转换

static关键字

static关键字是用来修饰成员变量和成员方法,被修饰的成员是属于类的,而不是单单属于某个对象的。既然说是属于类的,所以不需要创建对象来调用。

  • static修饰的内容,是随着类的加载而加载的,且只加载一次;
  • 存储于一块固定的内存区域(静态区),所以,可以直接被类名调用;
  • 它优先于对象存在,所以可以被所有对象所共享。

如下是静态static修饰过的内容的内存原理图解:
static内存原理图解

静态代码块

定义在成员位置,使用static修饰的代码块

  • 位置:类中方法外
  • 执行:随着类的加载执行且执行一次,优先于main方法和构造方法的执行
  • 作用:给类变量进行初始化赋值
public class Student{
	public static String name;
	public static ArrayList<String> list;
	
	static{
		//给类变量赋值
		name = "小可爱";
		//添加元素到list中
		list.add("小仙女");
	}
}

小贴士:
static关键字,可以修饰变量、方法和代码块。在使用的过程中,其主要目的还是在不创建对象的情况下,去调用方法。
静态方法可以通过实例化对象后,对象调用的方式完成非静态成员调用。

程序执行顺序

1.无论实例产生多少对象,静态代码块只执行1次
2.构造代码块随实例化过程调用
3.普通代码块随方法调用而执行

方法重写

子类出现了和父类一模一样的方法(返回值类型、参数类型、方法名)时,会出现覆盖效果。也称为重写或复写。声明不变,重新实现

子类覆盖父类方法,必须保证权限大于等于父类。

继承后的特点–构造方法

1.构造方法的名字和类名是相同的,所以子类是无法继承父类构造方法的;
2.构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中,默认有一个super(),表示调用父类的构造方法,父类成员初始化后,才可以给子类使用。

super和this

父类空间优先于子类对象产生

  • 在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于其子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
  • 理解图如下:
    在这里插入图片描述
  • super:代表父类的存储空间标识。(可以理解为对父类的调用)
  • this:代表当前对象的引用(谁调用就代表谁)

抽象类

继承抽象类的子类必须重写父类的所有方法。否则,该类也要声明为抽象类。最终,必须有子类实现父类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。

注意事项:
关于抽象类的调用,以下为语法上要注意的细节。虽然条目较多,但若理解抽象类的本质,无需死记硬背。

  • .抽象类无法创建对象,若创建,则编译无法通过而报错。只能创建其非抽象子类的对象。
    理解:假设创建抽象类的对象,则对象调用抽象方法,而抽象方法没有具体的方法体,无意义。
  • 抽象类中,可以有构造方法,是提供子类创建对象时,初始化父类对象使用的。
    理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
  • 抽象类中,不一定包含抽象方法;但有抽象方法的类一定是抽象类。
    理解:未包含抽象方法的抽象类,目的就是不想让调用者调用该对象,通常用于某些特定的类结构设计。
  • 抽象类的子类,必须重写父类的所有抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
    理解:假设不重写所有的抽象方法,则类中可能有抽象方法。在创建对象后,调用抽象的方法,没有意义。

继承的综合案例

  • 综合案例:群主发普通红包。某群有多名成员,群主给成员发普通红包。普通红包的规则:
    1.群主的一笔金额,从群主的余额中扣除,平均分成n等分,让群成员领取;
    2.成员领取红包后,保存到成员余额中。
    请根据描述,完成案例中所有类的定义以及指定类之间的继承关系,并完成发红包的操作。
  • 案例分析:
    根据描述,得到如下继承体系:
    设计

Collection集合的遍历

  • Collection接口提供了统一的遍历集合的方式:迭代器模式。通过iterator()方法可以获取一个用户遍历当前集合元素的迭代器(iterator接口)。
  • java.util.iterator接口:定义了迭代器遍历集合的相关操作,不同的集合都实现了用于遍历自身元素的迭代器实现类,但是我们无需记住它们的名字,从多态的角度把它们看成iterator即可。
  • 迭代器遍历遵循的步骤为:问(hasNext())、取(next())、删,但删不是必须操作
public class IteratorDemo{
	public static void main(String[] args){
		Collection c = new ArrayList();
		c.add("one");
		c.add("#");
		c.add("two");
		c.add("#");
		c.add("three");
		c.add("#");
		c.add("four");
		c.add("#");
		c.add("five");
		System.out.println(c);//[one,#,two,#,three,#,four,#,five]
		
		/**
		迭代器的常用方法:
		1)boolean hasNext()--------------问
			询问集合中是否还有“下一个”元素可共迭代
			注意:迭代器默认开始位置在第一个元素之前
			无论调用多少次hasNext()方法,迭代器的位置都不会改变
		2)Object next()---------取
			迭代器向后移动一个位置来指向集合的下一个元素并将其获取
		**/
		Iterator it = c.iterator();//获取集合c的迭代器
		while(it.hasNext()){//若有下一个元素
			//Object str = it.next();
			String str = (String)it.next();//获取下一个元素
			System.out.println(str);
			if("#".equals(str)){
				//c.remove(str);//会报错。迭代器在遍历的过程中,无法通过集合的方法增删元素
				it.remove(str);//删除next()方法所获取的元素
			}
		}	
		System.out.println(c);	//把#删掉啦。[one,two,three,four,five]
	}
}

增强for循环/新循环

集合遍历:iterator
数组遍历:for循环

可使用相同的语法来遍历集合和数组

增强for循环/新循环语法为:

for(元素类型 变量名: 集合或数组){ 循环体 }

举例如下:

for(Object num : list){
		//循环体
}

新循环遍历集合----会被自动转换成迭代器或者for‘循环数组遍历’

Collection相关方法

size():计算长度
add(Object e):添加
remove():删除给定元素
isEmpty():判断是否是空
clear():清空
contains(Object o)判断当前集合中是否包含元素o,包含返回true。
containsAll():判断一个集合中是否包含另一个集合的所有内容
removeAll():删交集
retainAll():取交集
addAll():将一个集合添加到另一个集合中
iterator():获取当前集合对应的迭代器
toArray():将当前集合转换为数组

泛型

  • 泛型也叫参数化类型,允许我们在使用类的时候,传入确切的某类型来规定其内部的属性、方法参数或返回值类型,使得我们使用时更方便。
  • 泛型在集合中被广泛使用,用来指定元素的类型。
  • 若不指定泛型的具体类型,则默认为Object
  • 若不指定泛型的具体类型,则在获取泛型的值时,编译器会补充强转操作
Collection<String> cc = new ArrayList<>();
cc.add("卡哇伊");

List接口

继承自Collection接口,List集合是可重复集合,有序,并且提供了一套可以通过下标操作元素的方法。

常见的实现类有两组:

  • java.util.ArrayList:内部使用数组实现,查询快(因为有下标,所以更适合查找和更新数组),但增删性能不好(删就要所有元素往前挪,增需要后面所有元素往后挪),只是在链表首部和尾部插入或删除非常有效。

  • java.util.LinkedList:内部使用链表实现,查询慢,(首、尾的)增删性能稍微好些、适合快速的插入和删除元素

注意:在对集合操作的增删性能没有特别苛刻的要求时,通常选择ArrayList

LinkedList

LinkedList实现List和Queue两个接口

  • 构造方法:
LinkedList() //构造一个空链表
LinkedList(Collection<? extends E> c)
 //构造一个包含指定Collection中的元素的列表,这些元素按其Collection的迭代器返回的顺序排列
  • 常用方法
boolean add(E e) //添加元素
void add(int index,E e)
boolean addAll(Collection<? extends E> c)//添加指定Collection的所有元素到此列表的结尾
boolean addAll(int index, Collection<? extends E> c)
//添加指定Collection的所有元素从此列表的index位置开始插入
void addFirst(E e)
void addLast(E e)
void clear()
boolean contains(Object o)
E get(int index)
E getFirst()
E getLast()
int indexOf(Object o)	//返回首次出现指定元素的索引,如不包含则返回-1
int lastIndexOf(Object o)	//返回最后一次出现指定元素的索引
E peek() //获取但不移除此列表的头,如列表为空则返回null
E peekFirst()
E peekLast()
E poll()	//获取并移除此列表的头
E pollFirst()
E pollLast()
E pop()	//从此列表所表示的堆栈中弹出一个元素
void push(E e)	//将元素推入此列表所表示的堆栈
E remove() 	//获取并移除此列表的头(第一个元素)
E remove(int index)		//移除此列表中指定位置的元素
boolean remove(Object e)	//从此列表中删除首次出现的指定元素
E removeFirst()	//移除并返回此列表的第一个元素
E set(int index, E e)	//将此列表中指定位置的元素替换为指定元素
int size()		//返回此列表的元素数
Object[] toArray()	//适当以返回元素(从第一个元素返回最后一个元素)包含此数组中所有元素的数组

集合和数组的转换

  • 集合转换为数组:Collection 的 toArray()
public class CollectionToArrayDemo {

}
  • 数组转换为集合: Arrays 的静态方法 asList()
public class ArrayToCollectionDemo {

}

接口

  • 接口是java语言中的一种引用数据类型,是方法的集合。如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要封装了方法,包括抽象方法(JDK7及以前)、默认方法和静态方法(JDK8)、私有方法(JDK9)。
  • 接口的定义,它与定义类相似,但是它用interface关键字。它也会被编译成.class文件,但一定要明确它不是类,而是另外一种引用数据类型。
引用数据类型:数组、类、接口
//定义格式
public interface InterfaceName{
	//抽象方法
	public abstract void method();
	//默认方法
	public default void method1(){//执行语句}
	//静态方法
	public static void method2(){//执行语句}
	//私有方法
	private void method3(){//执行语句}
}
/**基本的实现
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,或者说接口的子类。
实现的动作类似继承,格式相仿,只是关键字是implements.
非抽象子类实现接口:
1.必须重写接口的所有抽象方法;
2.继承了接口的,默认方法,既可以直接调用,也可以重写。
**/
class 类名 implements 接口{
	//重写接口中抽象方法(必须)
	//重写接口中默认方法(可选)
}

注意:静态与.class相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。代码如下:
定义接口:

public interface LiveAble{
	public static void run(){
		System.out.println("我是接口中的静态方法");
	}
}

定义实现类:

public class Animal implements LiveAble{
	//无法重写静态方法
}

定义测试类:

public class Test{
	//Animal.run(); //错误,无法继承方法,也无法调用
	LiveAble.run();//ok
}

私有方法的使用

  • 私有方法只有默认方法可以调用
  • 私有静态方法只有默认方法和静态方法可以调用

如果一个接口中有多个默认方法,并且代码中有重复,则可以抽象出来封装到私有方法中,供默认方法去调用。从设计的角度,私有方法是对默认方法和静态方法的辅助。

public interface LiveAble{
	default void func(){
		func1();
		func2();
	}

	private void func1(){
		System.out.println("跑起来~~~");
	}
	private void func2(){
		System.out.println("跑起来~~~");
	}
}

优先级问题

当一个类既继承父类,又实现若干个接口时,如果父类的成员方法与接口中的默认方法的方法名相同,子类就近选择执行父类的成员方法。代码如下:
定义接口:

public interface Aoo{
	public void methodA(){
	System.out.println("AAAA");
	}	
}

定义父类:

public class Boo{
	public void methodA(){
	System.out.println("BBBB");
	}	
}

定义子类:

class C extends Boo implements Aoo{
	//未重写methodA方法
}

定义测试类

public class Test{
	public static void main(String[] args){
		C c = new C();
		c.methodA();//输出结果:BBBB
	}
}

多态

多态是继封装、继承之后,面向对象的第三大特性。
多态:是指同一行为,具有多种表现形式。

前提:【重点】
1.继承或者实现【二选一】
2.方法的重写【意义体现:不重写,无意义】
3.父类引用指向子类对象。
格式:
父类类型 变量名 = new 子类对象;
变量名.方法名();

当使用多态调用方法时,先检查父类中是否含有此方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。

多态可以使程序变得简单,有良好的拓展性。

引用类型的转换

多态的转型分为向上转型和向下转型两种。

  • 向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
    当父类引用指向一个子类对象时,就是向上转型。
    使用格式:
父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();
  • 向下转型:
    当父类类型向子类类型向下转换的过程,整个过程是强制的。
    使用格式:
    一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat a =Cat)a;

转型的过程中,一不小心会遇到问题,如下:

public class Test{
	public static void main(String[] args){
		//向上转型
		Animal a = new Cat();
		a.eat();	//调用的是Cat的eat
		
		//向下转型
		Dog d = (Dog)a;
		d.watchHouse();	//调用的是Dog的watchHouse【运行报错】
	}
}

这段代码可以通过编译,但是运行时,却报出了ClassCastException,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换为Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。

  • 为了避免ClassCastException的发生,Java提供了instanceof关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false

所以 ,转换前,我们最好先做一个判断,代码如下:

public class Test{
	public static void main(String[] args){
		//向上转型
		Animal a = new Cat();
		a.eat();
		//向下转型
		if(a instanceof Cat){
			Cat c = (Cat) a;
			c.catchMouse();
		}else if(a instanceof Dog){
			Dog d = (Dog) a;
			d.watchHouse();
		}
	}
}

java是值传递的

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

程序执行的顺序:先new成员变量,再new构造方法等

基本类型与包装类型

  • 基本类型保存在栈中方便高效存取,包装类型需要通过引用指向实例,存在堆中
  • 与集合类型使用时只能使用包装类型
  • Java中的包装类包括:Integer、Long、Short、Byte、Character、Double、Float、
    Boolean、BigInteger、BigDecimal。其中BigInteger、BigDecimal没有相对应的基本类型,主要应用于高精度的运算,BigInteger支持任意精度的整数,BigDecimal支持任意精度带小数点的运算。
  • 在java中,一切皆对象。但八大基本类型不是对象
  • 基本类型无需new来创建,而包装类型需要new来创建
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Protobuf是一种高效的序列化协议,可以用于数据交换和数据存储。它的主要优势是大小小,速度快,可扩展性强。下面是使用Protobuf的一些小记: 1. 定义消息格式 首先,需要定义消息格式,以便Protobuf可以将数据序列化和反序列化。消息格式定义在.proto文件中,使用protobuf语言编写。例如,下面是一个简单的消息格式定义: ``` syntax = "proto3"; message Person { string name = 1; int32 age = 2; } ``` 这个消息格式定义了一个名为Person的消息,包含两个字段:name和age。 2. 生成代码 一旦消息格式定义好,就可以使用Protobuf编译器生成代码。编译器将根据消息格式定义生成相应的代码,包括消息类、序列化和反序列化方法等。可以使用以下命令生成代码: ``` protoc --java_out=. message.proto ``` 这将生成一个名为message.pb.javaJava类,该类包含Person消息的定义以及相关方法。 3. 序列化和反序列化 一旦生成了代码,就可以使用Protobuf序列化和反序列化数据。例如,下面是一个示例代码,将一个Person对象序列化为字节数组,并将其反序列化为另一个Person对象: ``` Person person = Person.newBuilder() .setName("Alice") .setAge(25) .build(); byte[] bytes = person.toByteArray(); Person deserializedPerson = Person.parseFrom(bytes); ``` 这个示例代码创建了一个Person对象,将其序列化为字节数组,然后将其反序列化为另一个Person对象。在这个过程中,Protobuf使用生成的代码执行序列化和反序列化操作。 以上是使用Protobuf的一些基本步骤和注意事项,希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值