java属性的理解
比如如下的代码:
public class User { private Integer id; private String username; private String password; private Integer age; private String sex; public User() { } public User(Integer id, String username, String password, Integer age, String sex, String email) { this.id = id; this.username = username; this.password = password; this.age = age; this.sex = sex; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getEmail() { return email; }}
属性看似是private String sex;这种为属性,但实际上真正的属性是get和set方法定义的:比如sex是由getSex或setSex去掉get和set之后变为Sex然后再将首字母变为小写即为最终的属性结果,这才是真正的属性,就比如我设置private String sex=0;,但是我的getSex和setSex根据0或1返回男或女,那此时男女才是真正的属性值。
这也就是为什么pojo中必须要设置get和set方法并且有一个无参构造,框架使用get和set进行操作,而将虚拟属性作为private。
java的局部变量的作用域问题
java变量也和python差不多的,只不过以一个{}为作用域,出了{}变量会立刻释放,也就和python一样,从自己作用域-》父作用域-》全局作用域这样找,兄弟作用域因为不可能同时启用并且会释放所以肯定是无法相互访问的
区别点在于for if这种带{},当然有自己的作用域,python中他们都没有自己的作用域
java中单引号双引号的问题
单引号只能括住一个字符,且单引号内也只能有一个字符,表示为char
双引号能括住任意数量的字符0~N,表示为str
所以单双引号要严格区分来使用
+=号和普通加法的区别
a+=0.2 就可以转换成a=a+0.2,但还有微小差别
int a=5a+=0.2 //可以通过,+=并不不会改变数据的类型,得到5,相当于默认来了一次强转a=a+0.2 //编译不能通过 因为a+0.2得到doubel类型结果,没有强转不能赋给int的
&和&&的区别
&如果前为假后面还会接着执行
&& 如果前为假后面则直接不执行了,反正一定是为假了
|与||同理
&& 当然是优先使用的
自动类型转换
byte+byte=int
char+byte=int
short+char=int
byte、char、short无论怎么运算都会得到int结果
只有低容量向高容量可以自动转换(也就是右向移动),否则必须强制转换,要不就报错,系统并不会帮你强转
子类-》父类 也可以自动转换,但父类想要升级为子类那必须进行强制症状
Break和continue
一个是结束一层,相当于让整个switch,for,while失效,一个是只让当前这一轮失效,也就是for、while循环后面的轮还是要执行的
java数据类型
有基本数据类型和引用数据类型
这里可以和python相比较,基本数据类型在赋值时是栈内新建内存空间进行赋值,引用数据类型就同python可变对象,因此传入基本数据类型在函数中无法改变外部的值,但传入引用数据类型可以
4种权限修饰符
需要注意的点:
private:指的是该类内部,如果是A类内部定义了私有的a,那么只有定义A的那个{}才能调用a,就连继承A的子类B都无法在B的{}内直接调用a,即便B继承了他。
私有属性可以被子类继承,只是无法在子类内访问罢了
其他的就子类就正常继承就行了,不会像private有什么问题
protected:指在不同包下,如果A是B的子类,那么A还是可以访问B的protected成员和属性的
继承
继承会获取父类所有的属性和方法,同时继承的属性和方法相对于子类权限会改变。
关于方法的结构/重载与重写的区分
一共由5个部分组成
同名形参列表不同的定义叫重载,同名且参数列表相同的方法在子类进行重写叫覆盖override/重写
同名且参数列表相同的函数不可能同时存在两个的,因为这样就无法知道调用的时候用的是哪个
方便记忆:重载就是多个载,就是一个函数同时有多个含义,也就是重载
重写,覆盖就是新的覆盖旧的。
构造器
开头默认调用super(),可以自己指定super或this此时默认的会失效,且调用别的构造器只能一次。
第三点非常重要,首行肯定要有构造器的调用,没有则使用super(),但一定要有一个,且仅有一个。
默认初始化
注意点
局部变量(包括引用)不会分配默认值,在使用之前必须初始化
类中的属性会最初分配默认值,可以不初始化,也可以不使用默认值,直接在定义成员时直接进行赋值,python,java都可以的
static的成员无法被默认初始化,因此必须手动初始化比如在代码块,构造器,或定义时就赋值
默认初始化
1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。
2、单精度浮点型(float)的基本类型变量的默认值为0.0f。
3、双精度浮点型(double)的基本类型变量的默认值为0.0d。
4、字符型(char)的基本类型变量的默认为 “/u0000”。
5、布尔性的基本类型变量的默认值为 false。
6、引用类型的变量是默认值为 null。
7、数组引用类型的变量的默认值为 null。当数组变量的实例后,如果没有没有显示的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。 、
可以使用默认初始化的类中非静态属性,数组,像下图所示
equals和==的区别
见尚硅谷,这个还有点坑,如果调用的是object的equals那么和==没有区别,想string,Date这种重写了equals那么比的就是内容
==对于基本数据类型比的不是地址而是值!
嵌套相同的类 、类中类
1.单例中的类中类:比如A类中有一个成员A,是可以的,但成员A必须先设置为null,或者说再构造器或者默认时成员A不能为非空,否则会发生成员A创建好后里面还有他的成员A,又要调用构造器,陷入了无限递归之中。
也就是A类的成员可以有A,但不能在初始时或构造器内为其进行创建,只能为null。
枚举中的类中类:我在A类中定义A类成员,这些成员他们都是静态的,只会创建一次,并不会出现循环调用的问题,如下图所示这些成员A类的内部当然也会有静态的A,但是这些都会指向自己也就是指向方法区的他们四个,这四个都存在于方法区。
属性初始化优先级,属性初始化流程
可以看到显式初始化和代码块是平级的,先后取决于他们两个谁更靠上
需要注意的是123都叫做初始化,但4叫做赋值,也就意味着final类型的属性无法被4修改,但可以被123初始化
默认初始化每个对象都会最开始做的,见默认初始化章节。
final修饰
表示最终的
(对于类和方法都关于继承)
对于class 表示该类无法被继承
对于方法表示该方法无法被重写
对于变量 (注意如果是引用的话就是地址值无法改变,但内容还是可以改变的,比如arraylist 我在不改变地址的基础之上使用arraylist.add都是可以实现的)
对于属性表示无法赋值 ,可以初始化
对于局部变量直接表示为常量
尤其对于形参,表示其为常量,初始化后就无法更改了
statistic final 对于属性表示全局常量
abstract
用于方法和类,因为总是和方法重写相关,abstract的方法子类必须要重写(覆盖)该方法,abstract不能被修饰private(也无法重写)、静态方法(不算重写,并不会表现出多态,调用父类引用调用的还是父类的静态方法,并非子类的)、final(方法使用final无法被重写)的方法使用
接口
接口实际上就是定义了一种规范!这句话非常重要,就比如jdbc中的druid包的DruidDataSource是实现了规范DataSource,mysql以及各种各样的连接器也都实现了连接接口,遵循连接的方法规范。都实现了相同的方法,更好移植程序和统一方法
接口中所有变量都是public static final
变量都是public abstract,意味着所有方法都必须被继承才行。
枚举类:enum
写法示例
原始写法
注意class改成enum,public static final定义的共享常量可以简化写法,写为变量名+ 初始化方法,写在最上面
编码解码
编码:a->编码方式->字符流
解码:字符流->解码方式(实际也是编码方式的逆向)->a
classloader
是类加载器,可以读取编译好的字节流class文件,因此有重要读取字节流方法getResourceAsStream
内部类
也就是只有该类会使用某个类,可以将其定义为内部类,比如只有人会打游戏,那么可以将打游戏类定义为内部类,想要从外部调用,可以使用调用new Person.Playgame(),创建实例,且Playgame内部可以调用Person的方法属性等,因为他的{}父作用域就为person,可以将Playgame这个类当做成员或方法来看待或调用
String
可以看到String内部维护了一个不可改变指向的char数组,意味着比如
a=“123”
a=“456”
此时String就必须新建一个对象赋给a
字符串对象的地址输出的都是char数组的地址!
字符串对象的地址是无法获得的,都总是输出char数组的地址,也就是方法区的地址
就比如这个题,虽然new 了两个String,但是他们两个都指向同一个字符串常量池中的char数组,因为对于String,char数组的地址就代表了String的地址,所以这里还是会添加失败的。
就把String当做char数组来看就好了!!
泛型
使用泛型要有两个步骤,声明和绑定
类的泛型
泛型的声明:如图所示,要在类名的地方声明用到了哪些泛型,把所有泛型都列出来
泛型绑定:写构造器时对K和V进行绑定。
方法的泛型
泛型声明在返回值之前,后面Class
泛型的灵活性、省略
比如在上文我新建Node对象时这样写
new Node<>(xxx,"abc","cde",null)
我尖括号中并没有写值,只有在"abc","cde"传入时才知道k和V是String类型,如果这里写死的话就只能传特定类型,就没有灵活性了。
这样写二者等价
ArrayListobjects = new ArrayList<>();ArrayList objects = new ArrayList ();
也就是new 时的类型泛型可以省略,因为前面已经指明了泛型的类型,因此这里可以省略。
Java软件包和普通文件夹的区别
Java软件包是一种特殊的文件夹,它可以存储类、接口、枚举和注释等类型,而普通文件夹只能存储文件。
Java软件包可以提供命名空间管理和访问控制的功能,避免类名冲突,方便类的查找和使用。普通文件夹没有这些功能。
Java软件包需要在源文件中用package语句声明,而普通文件夹不需要。
Java软件包中的类需要用import语句导入才能使用,而普通文件夹中的文件不需要。
也就是.java文件必须存在包下,便于管理,使用的话import导入等等