JAVA基础

标识符

规则:
1,由数字,字母,_,$ 组成
2,不能由数字开头
3,区别大小写,无长度限制
4,符合“见名知意”,不能与关键字重名

关键字

用作专门用途的字符串
在这里插入图片描述

常量值

:区分为不同数据类型。
1,整型常量,123
2,实型常量,3.14
3,字符常量,’a’
4,逻辑常量,TRUE
5,字符串常量,“abc”

变量

:内存中一小块区域,用它的名字来访问内容。
位置
1,局部变量,方法内部定义
2,成员变量,方法外、类内部定义
数据类型
1,基本数据类型 :数值/字符/布尔型(不能0/1表示)
2,引用数据类型:类/接口/数组

byte,short,int,long,float,double—1,2,4,8,4,8字节
浮点数表示形式:1,十进制 2,科学记数法,3.1e2

进行运算时,只能容量小的类型向大的自动转换,从小到大:
byte,short,char < int < long < float <double
(与字节数无关)
byte,short,char运算时都会转为int。所以并不需要为了省资源而使用byte,相反,虚拟机要去判断它们的精度,增加开销。
多种类型混合运算,系统自动转换成容量最大的类型,再运算。

注意:整数默认是int,浮点数默认是double。
强制转换时,要注意溢出。

程序执行过程

在这里插入图片描述

接口

接口中的属性都默认是public static final的,原因:
1.接口是一个模板,它的成员是它的实现类所共享的,所以必须是public;
2.为避免一个类实现的多个接口中有同名变量,故用static,便能通过A.str,B.str来区别;
3.接口是最高层次的抽象,是一种规范、功能定义的声明,所有可变的东西都应该归属到实现类中,这样接口才能起到标准化、规范化的作用。接口也是一种协议,如果所有的实现类都能改变接口属性的值,则违反了OCP协议。

ps:与变量必须为static相反, 方法不能为static,否则当多个方法实现该接口时,若调用 【接口.方法】,就无法判断要调用哪一个方法了。

static

static关键字:变量方法存储在内存的方法区中,而非静态则在内存的堆中。(ps:实例对象在堆中)故两者生命周期不一。

生命周期:区别于非静态事物(变量和方法),在类被加载时候就存在,而非实例化对象时;在类消失就销毁,而非对象销毁时。
(由此,静态方法中不能调用非静态事物,除非已经new了一个对象,否则,当不存在对象时,若使用【类.方法】调用,由于非静态事物是随着对象存在而存在的(进入内存),故会出错。)

使用规则:
1、static 的方法只能访问静态属性/ 方法(除非已new对象);非static 方法既能访问静态属性方法、也可以访问非静态属性方法;
2、非静态/静态方法都不能定义静态变量;(这是规则。因为方法内的变量的局部变量,它的生命周期是跟随该方法的;而static成员是全局的、共享的类成员,它的生命周期是跟随类的。
3、静态方法中不能使用this关键字。(因为this代表了一个对象,而此时不一定有对象
4、静态内部类(即嵌套类)不能访问外部类的非静态成员;
5、普通内部类只能定义非静态变量、非静态方法、非嵌套类;而静态嵌套类可以定义静态和非静态变量、静态和非静态方法、静态和普通内部类。
6、非静态内部类不能定义静态成员,因为它的实例化是在外部类实例化之后才加载的。如果外部类还没有实例化,这时候调用内部类的静态成员,此时内部类还没有被加载,却要开始创建静态成员,这是矛盾的。

个人总结:
静态对象可以定义非静态成员、但不能调用非静态成员(除非已经new了该对象,参考main函数);
非静态对象可以访问静态成员、但不能定义

注:没有外部静态类,内部静态类的出现是为了区别多个内部类,而外部类永远只有一个,所以不需要再加static来混淆。

使用静态内部类的原因:(个人觉得)
1、可以定义静态成员
2、静态内部类数据对外围对象可见
使用普通内部类:
1、可以调用外围对象所有成员,以此实现Java独特的“多继承”。
2、同样,数据对外围对象可见,依赖外部类,也可以访问外部类数据

另外:
1、对于静态字段,只有直接定义这个字段的类才会被初始化。当通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化;当然,如果通过子类引用子类中定义的静态字段,父类亦会先初始化(Java类继承的规则)
2、采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“类名.方法名”的方法去调用类方法了,直接可以采用"方法名"去调用类方法,就和调用类自己的方法一样
3、static代码块是独立于成员变量和成员函数的代码块。只会在JVM加载类时会执行这些静态的代码块,且只被执行一次
4、static修饰的成员称为类成员(生命周期与它的类相同),否则称为实例成员
5、类成员在内存中只有一个,用于数据共享;而实例成员则每个对象都有一个

为什么main方法可以加final修饰符,也可以改参数,但一定是public、void、static的

1、public允许从类外部调用该类成员,而虚拟机显然是从类外部调用main方法的,故用public;
2、作为调用者,虚拟机启动Java程序时,只需要调用main方法而无需返回值,故用void;
3、使用static,可以让虚拟机无需创建实例就调用main方法。(类被加载就存在

final修饰符

1、**变量:**在修饰引用变量的时候,这个不变是指的其引用不变,但引用的对象的内容是可变的。而在修饰基本变量如int时,则意味着这个基本类型的值不能改变。但,final在修饰String类的对象时,其值和修饰基本变量类型是一样不能改变的。(不可变类?
2、方法: final方法只能被继承,不能重写;private方法都是隐式的被指定为final 的
3、类: final类不能被继承

重载、重写

重载的任一条件:(不覆盖)
1、参数数量一样,类型不一样
2、参数数量不一样
3、参数数量一样,相同位置类型不一样
注:只有返回类型不同,是不能重载的
**重写:**与其父类的方法名、方法参数、参数类型、参数位置完全相同(返回类型可不同)。(覆盖)

transient关键字


实现了Serilizable接口的类的某个变量不想序列化时,就可用transient修饰;
实现方式:这个变量仅存于调用者的内存中而不会写到磁盘里持久化。
被修饰的变量,序列化后无法再访问(应该是因为没有被持久化吧==)、也不能再被序列化
本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
静态变量不管是否被transient修饰,均不能被序列化。(毕竟还没实例化就已经被加载了

权限控制关键字public、default、private、protected

在这里插入图片描述

==跟equals()跟compareTo()的区别

==:比较的是引用地址。ps:对于基本数据类型,比较的是值;对于复合数据类型,比较的则是引用地址。
例如String类型,由于java中的字符串缓冲池机制,使用String s1 = “a”;是直接到池中去取,而String s2 = new String(“a”);则是创建一个新对象。内存地址不同,因此当用此符号比较,会返回false。
equals():比较的内容。只要内容相同即为true。如上例,会返回true。

compareTo():有两种用法:

int compareTo(Object o) 


int compareTo(String anotherString)

返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值;否则,第二个字符和参数的第二个字符做比较…以此类推,直至比较的字符或被比较的字符有一方结束。

Integer与Int的比较

Integer是Int的包装类,而Int是Java的一种基本数据类型。
Integer需要实例化才可以使用;Int不需要。
Integer实例化之后生成指针;Int直接储存值。(ps:区别于数组等引用类型,当做传参在方法中被改变后,它本身不会改变。因为String是不可变类。不可变类如果改变了是被重新给了地址【一般是重新创建一个对象,并将指针指向新对象】,而不是改变地址中的值。【其他的不可变类也是如此,如Integer、Double等基本类型的包装】)
Integer默认为null;Int默认为0。

Integer实例化的三种方式:
(ps:类似于String,当使用方式1/方式3创建对象时,使用享元模式,但局限于-128~+127范围内)

Integer num= 130; 
Integer num = new Integer(12); 
Integer num = Integer.valueOf(12);

注意:(使用==比较时)
1、new的两个值相同的Integer对象,比较结果为false,因为引用地址不同;
2、new一个Integer对象,值与某个Int类型的值相同时,比较结果为true,因为比较时Integer类会自动拆包装;
3、由于常量池的使用,当以非new方式来创建范围-128~127的值,比较结果为true。

取整的三个方法

Math.ceil()    //表示向上取整
Math.floor()    //表示向下取整
Math.round():    //四舍五入

面向对象的特征

1、封装:将对象的属性和方法的代码封装到一个模块中,也就是一个类中,并且利用访问限制修饰符来保护成员变量,如private;
如果外界要对某些变量 or 方法进行访问 /调用,再建立 public 访问方法;
2、抽象:找出一些事物的相似和共性的行为和特征,归为一个类。抽象包括行为抽象和状态抽象。
3、继承:在已经存在的类的基础上进行修改和扩展。
4、多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
如:当子类重写了父类的方法,引用了父类的子类对象和父类对象调用该方法时;
或是不同的实现类对接口的方法进行不同的编写,引用了接口的不同实现类对象调用该方法时。

接口与继承

接口:当多个类的处理目标相同但方法不同时使用;
继承:当多个类具有某些相同功能时使用;

联系:都提高了代码的可复用性,提高了开发效率。
区别:
1、修饰不同;implements与extends
2、数量不同;多个与一个
3、属性不同;只能定义public static final 的变量与空方法;在继承中能定义其他类型变量、常量等
4、调用不同。实现接口必须实现所以方法;继承可以按需使用

String、StringBuffuer、StringBuilder

String:字符串数值不可变。由其不可变类的特性,效率最低;
StringBuffer:字符串可修改,可以动态构造字符数据。可以通过Append()来修改值。线程安全。
StringBuilder:区别于StringBuffer:线程不安全,但效率最高。

Java中线程的实现方法

1、继承Thread类。
2、实现Runable接口。
3、线程池获取。
4、实现Callable接口,重写call函数

Callable接口和Runnable接口的不同之处:
1.Callable规定的方法是call(),而Runnable是run();
2.call方法可以抛出异常,run方法不行;
3.Callable对象执行后可以有返回值,运行Callable任务可以得到一个Future对象,通过Future对象可以了解任务执行情况,可以取消任务的执行,而Runnable不可有返回值。

Thread的sleep()、join()、yield()与Object的wait()

sleep():可用于任何时候。让出CPU资源,进入阻塞状态(线程睡眠),但不释放资源🔒。使用该方法时必须用catch块捕获InterruptedException异常。无锁时,该方法能让低优先级线程获得执行机会。

wait():只能用于同步方法/同步块。让出CPU资源,进入等待队列(线程挂起),会释放资源🔒。当线程被notify()或时间满后,需要重新获得对象锁才能继续执行。
wait()方法、notify()方法和notiftAll()方法用于协调多线程对共享数据的存取。

join():表示当调用的线程执行完再继续向下执行。该方法也需要捕获异常。

yield():类似sleep(),但它不会阻塞进程,而是转换成就绪状态,等待调度器重新调度。
注:它不会让更低优先级进程有执行机会。

同步与异步

同步:发送一个请求,等待返回,然后再发送下一个请求。
如:1. Synchronized;2.wait和notify。
异步:发送一个请求,不等待返回,随时可以再发送下一个请求。

List、Set和Map的区别

List:是存储单列数据的集合。继承Collection接口。允许重复,存储有顺序
Set: 是存储单列数据的集合。继承Collection接口。不允许重复
Map:存储键和值这样的双列数据的集合,存储数据无顺序键(key)不能重复,值(value)可以重复

HashMap与Hashtable(待补充…)

java创建对象的方式有哪些(待补充…)

assert

在调试程序时使用,对一个boolean表达式进行检查。
为true,则程序正确,如果为false,系统则给出警告或者退出。

向上/向下转型

1、向上转型:父类引用指向子类对象:Parent parent = new Child();

注:

(1)不需要强制转型。

(2)有方法重载时,调用的时子类中重载的方法;若要调用父类中的方法,使用super;

(3)只能调用父类中的属性方法,不能调用子类独有的属性方法。

优点:

提高代码复用性。函数方法直接将父类作为参数,调用时可传子类对象;否则每个子类都要写一个方法。体现了java的抽象编程思想。

2、向下转型:把指向子类对象的父类引用赋给子类引用。

注:

(1)需要强制转型;

(2)不安全。一定要先向上转型之后才能向下转型。否则编译时无错,运行时报错。如:

	Parent parent = new Child();    //正确写法
	Child child = (Child)parent;   

	Parent parent = new Parent();  //错误写法,运行报错
	Child child = (Child)parent;  

优点:

父类和子类中的属性方法都可以调用。

ps:对于接口来说,当使用接口对象指向实现类时,同样,该对象不能调用实现类中特有方法。

泛型

泛型类、泛型接口、泛型方法

作用:用于多种数据类型执行相同的代码
ps:泛型之前用Object来实现,后要做强制的显式类型转换,很容易出现编译能过、运行出错的情况。

在 JDK1.5 之前,集合是没有泛型的,添加的数据都是 Object 类型,取出数据时,就要类型强制转换;如:若输入一个String类型数据,后方却将其强制转换后赋值给一个 integer 类型变量,这个时候,编译并不会报错,但运行就会出错,即存在安全隐患;

为了解决这个问题,引入了泛型——使用参数化类型,使用时就指定类型,编译期就能进行类型安全检查,不用再进行强制类型转换。更加安全。
ps:编译后虚拟机依旧是将其类型擦除为Object。

ps:
泛型类型参数不能为基本数据类型,如上所说,编译时会擦除类型为Object,而基本数据类型不是Object(对象)。

泛型数组只能声明,不能实例化。所以要用泛型尽量使用List。

原因:如果数组定义为泛型,在编译时亦会擦除为 Object[] ,实例化后,数组中的每一个Object对象都需要创建,创建时又可以使用不同的参数类型的泛型去创建,此时即失去了编译时的安全类型检查。
运行时又有可能发生ClassCastException 这与引入泛型的初衷相违背了。

博主认为:maybe对于非数组的泛型类型来说,从一开始就指定了类型,所以类型擦除前会检查要加入的数据类型是否正确;而对于数组类型 如 List[] list,类型擦除前并不会去检查数组中的每个泛型对象创建时的指定类型是否正确,所以如果使用会有安全隐患。

而对于 T [] t 这种泛型数组,也不可以被实例化,原因是数组的类型必须是一开始就指定的。
同样的,T泛型类也不能被实例化,因为编译时不确定参数化类型,也就找不到相应的字节码文件。

如果非要实例化泛型数组,有以下方法:

1、使用通配符参数,即 List<?>[] list = new List<?>[10]; 这样是可以的,因为这种方式最后取出时候要开发者自己主动进行显示类型转换,符合预期逻辑;
(即开发者自己清楚数组中存放的是什么类型,取出时赋予的对象类型与转换的类型都要写对;要注意,如果这两个类型都写错,依然存在强转类型出错的安全隐患,即编译通过运行出错。这就跟上面使用泛型数组的隐患一样了,所以说这种方式依然是不安全的)。

2、创建数组时,使用 new Object[] 来创建,后面取出时再强转为实际类型,因为Object 是引用数据类型的父类。
可用,但你想想泛型引入的原因,这种方式依旧不安全。

3、在方法中只声明,在构造方法或其他方法中需要时再从外界传入已经确定的某个类型的数组对象,再赋值给方法中的变量即可。
ps:要等待外界传入,限制多。

4、利用反射机制 ,使用java.lang.reflect.Array.newInstance(Class componentType, int length) 方法来创建一个具有指定类型和维度的数组。反射耗时。

	private T[] array;
	
        public ArrayWithTypeToken(Class<T> type, int size) {
                array = (T[]) Array.newInstance(type, size);
            }

ps: 博主尚未使用过这种方式,不太了解,不做评价。

为什么要有 get/set 方法

1、遵循面向对象编程的封装性——开发者应尽量隐藏类的内部实现细节,只对外提供接口;使用者并不关心内部设计,只关注提供的方法;

2、提高安全性。类中的某些属性是 readonly的,这时候只提供 get()方法便能实现对该属性的保护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值