**成员变量:**在类体之中、方法之外的变量称之为成员变量。成员变量如果没有手动赋值的话,系统会自动赋予默认值(一切向“0”看齐)。成员变量又分为:
-
实例变量(没有static修饰符)
-
静态变量(有static修饰符)
**注意:**类也是一种数据类型,属于引用数据类型,它的类型名称就是对应的类名。
2、对象创建和内存分配
对象就是类实例化之后的具体个体,类到对象的过程称之为实例化,反过来,对象到类的过程则称之为抽象。
**new关键字:**Java中使用new关键字来创建一个对象,new关键字也是Java中的一个运算符。
**内存分配:**当在方法区内存中的代码执行时,会在栈内存中开辟一块该方法对应的内存空间,而在方法执行过程中使用new关键字创建一个对象时,则会在堆内存中开辟一块该对象对应的内存空间。所以方法中定义的局部变量是在栈中的,而创建的对象则是在堆内存中的。实例对象每一个对象都会有自己的一块内存空间,即100个对象就会分配100个内存空间。
**指针屏蔽:**Java中想要访问堆内存中的数据,必须通过引用,而不能直接操作堆内存,因为Java中屏蔽了指针的概念,不能通过指针的方式直接访问或操作内存中的数据。
**访问属性:**对于实例变量属性的读取和修改,使用语法格式“引用.变量名”进行读取,使用语法格式“引用.变量名=值”对属性进行修改。注意,实例变量存储在堆内存中对应的实例对象内部,且不能通过类名的方式来访问。
3、空指针异常NullPointerException
当一个引用类型的变量的值不再是指向某个对象的内存地址,而是null,此时再去访问对象的相关属性或方法就会发生空指针异常,因为此时的变量不再指向该对象,而是值为null了,无法去访问该对象了,更不要说访问对象中的属性和方法了,空引用访问实例相关数据就一定会出现空指针异常。
4、get方法和set方法
**属性私有化:**在封装特性中,类中的所有属性都应该使用private修饰符进行修饰,private表示私有的,表示此属性只有在本类中才能访问,在类的外部不能访问。但是在类中应该为外部访问这些属性提供一些简单的公开的(public)操作入口,如对应的get方法和set方法。
get方法和set方法的写法如下:
// get方法
public 返回值类型 get+属性名首字母大写(){
return 属性名;
}
// set方法
// 注意,形参的名字如果和属性名相同了,那么属性名前面应该加一个this关键字
// 因为不加this关键字的话,由于名称是相同的,Java的就近原则会认为它俩都是同一个局部变量,即形参
public void set+属性名首字母大写(形参列表){
属性名=形参值;
…
}
示例:
public class A{
private int age;
public int getAge(){
// 这里可以使用this.age,也可以不用this
// return this.age
return age;
}
public void setAge(int age){
// 这里因为形参和属性名相同了,所以必须用this加以区分
this.age = age;
}
}
**注意:**get和set方法是没有static修饰符的,使用的是public修饰符,没有static修饰符的方法的访问方式为“引用.方法名(实参)”。
5、引用参数的传递
对象变量通常也称之为引用,因为在栈中这个变量只是个局部变量,而对象变量的值是该对象在堆内存中的内存地址,当然,这个内存地址则指向堆内存中的该对象实例。所以对于基本数据类型,值的传递不会影响到原本变量的值,但是对于类的实例,因为传递的值是内存地址,所以它虽然不会影响原本局部变量的值(即内存地址),但是如果对内存地址中的对象实例进行修改则会影响到内存地址指向的实例对象,即原本的局部变量指向的实例对象会被修改。
6、构造方法(constructor)
语法如下:
// 构造方法,也称为构造器(constructor)。
// 构造方法是不用也不能指定返回值类型的。
// 注意,构造方法名必须和类名相同,所以这里的语法就直接写类名了。
[修饰符列表] 类名(形式参数列表){
构造方法体;
}
示例:
public class A{
private int i;
// 下面的两个构造方法使用了方法的重载机制
public A(){
System.out.println(“类A的无参构造方法!”);
}
public A(int i){
// 使用this关键字区分实例变量和方法的局部变量
this.i = i;
System.out.println(“类A的有参构造方法!”);
}
}
**构造方法的调用:**构造方法的作用是通过调用构造方法来创建对象并初始化实例变量的值,而构造方法的调用使用new关键字“new 构造方法名(实参列表)”,注意new之后调用的其实是构造方法名而不是类名,但因为两者是相同的,所以可能会让人误以为调用的是类名。
**构造方法返回值:**虽然没有指定返回值类型,但是构造方法的返回值类型就是其所在类的类型,返回值就是新创建的对象的引用,但是注意的是这个返回值是不需要开发人员手动编写的,即构造方法的定义中,返回值类型和返回值都不需要人为的去定义。
**默认构造方法:**当类中没有定义构造方法时,系统会给该类提供一个无参数的默认构造器。需要特别注意的是,如果类中提供了构造方法,那么系统就不再为这个类提供默认的无参数构造方法了,所以,如果在类中提供了自己的构造方法,那么推荐手动将无参的构造方法加上,因为这个构造方法太常用了。
关于构造方法,还应该注意以下几点:
-
构造方法支持重载机制。
-
因为实例变量是属于实例的,所以构造方法是先创建对象再初始化实例变量。
7、this关键字
其实每一个实例对象中都有一个this变量,this中保存的是自身所在实例对象的内存地址,即this是指向实例对象本身的一个引用类型的变量。可以换一种方式理解,this可以出现在实例方法中,而方法中的this代表当前正在执行这个方法动作的实例对象。
在实例方法中对实例变量的访问,由于它是实例变量,所以不使用this关键字也是可以访问的,所以this在多数情况下是可以不写的。this主要用于区分实例变量和局部变量,比如setter方法和构造方法中就比较常用。
当然,this不能在含有static修饰符的方法中使用。
this关键字除了使用“this.xxx”的方式表示实例对象的使用之外,还可以在构造方法中以“this(实参列表)”形式表示调用本类的另一个构造方法,但是注意,使用这种用法时这个语句只能出现在构造方法的第一行(当然这个语句之后可以添加其他的语句,但前面就不能有其他任何语句了),如:
public class User{
private int age;
public User(int age){
this.age = age;
}
public User(){
// 此处表示调用另一个构造方法
// 但是注意,这个语句只能是此构造方法的第一个语句
this(18);
// 之后可以加别的语句
System.out.println("my age is " + this.age);
}
}
8、super关键字
super关键字和this关键字在用法上有许多相似的地方,但是this代表的是当前实例对象,而super代表的是当前子类的父类的特征(包括属性和方法),通常用于访问父类的某些属性和方法。和this对比着看,它们的相似之处如下:
-
super用法也有两种:”super.“和”super()“。
-
super也是只能出现在实例方法和构造方法中,不能在静态方法中使用。
-
super在大多情况下也是可以省略的,除非特定指明需要使用父类中的属性或方法的时候才使用。
-
super()这种用法也是只能出现在构造方法的第一行,通过当前的构造方法去调用父类的构造方法,super的一个作用是代码复用,另一个作用是在创建子类对象的时候先初始化父类的特征(属性等)。父类的特征如属性因为大多是private,并不能通过直接赋值来初始化,此时就需要使用super来调用父类的构造方法来进行初始化了。
对于super()这种用法,当一个子类的构造方法的第一行既没有this(),也没有super(),那么默认会有一个super()执行,表示在子类的构造方法中调用父类的无参构造方法,此时必须保证父类必须有一个无参构造方法,推荐在类的定义中都手动写好一个无参的构造方法。当然,要是你自己手动调用了this(实参列表)或者super(实参列表),程序就会按照你写进行调用了。示例如下:
public class TestSuper{
public static void main(String[] args){
// 执行结果:
// 类A的无参构造方法!
// 类A的无参构造方法!
new B();
}
}
class A{
public A(){
System.out.println(“类A的无参构造方法!”);
}
}
class B extends A{
public B(){
// 由main方法的输出可以看出类A的无参构造方法也是被执行的,
// 其实如果没有手动调用super(),此处会默认执行一个super()
// super();
System.out.println(“类B的无参构造方法!”);
}
}
关于super的使用,注意以下几点:
-
Java中允许在子类中出现和父类一样的同名变量或同名属性,此时,如果想要在子类中访问父类的这个同名的属性,就需要使用“super.xxx”的形式去访问了。
-
super不是引用,保存的也不是内存地址,也不指向任何对象,只是代表当前对象内部的父类特征。
9、继承
**继承特性优点:**继承最基本的作用是代码复用,但是最重要的作用却是有了继承才有了方法的覆盖和多态机制。
**单继承:**Java中的继承机制只支持单继承,一个类不能同时继承多个类,只能继承一个类。语法如下:
// 继承使用extends关键字
[修饰符列表] class 类名 extends 父类名{
类体;
}
可以继承的数据:
-
private私有的不支持继承。
-
构造方法不支持继承。
-
其他数据可以被继承。
**多继承:**Java中虽然只支持单继承,但是可以间接实现多继承:
C extends B{
}
B extends A{
}
A extends T{
}
// 这样C直接继承B,但间接继承了T和A类
**默认基类:**Java中一个类如果没有显式继承任何类,那么该类默认继承javaSE库中提供的java.lang.Object类。
需要注意一个概念,当一个子类在继承某个父类时,在运行时,不是说在子类中查找对应方法或属性,子类中没有再到父类中查找,而是在定义时,如果继承了某个父类,那么这个类的定义中就包含了父类继承过来的某些方法和属性,即子类对象执行的方法和属性总是自己的属性和方法。
10、方法的覆盖/重写(override)
方法的覆盖也称为方法的重写,子类将父类继承过来的方法进行重新编写被称为方法的重写,方法重写时需要注意:
-
方法重写发生在具有继承关系的父子类之间,且是可以继承的方法上(私有的以及构造方法不能继承,也就不能进行重写了)。
-
重写时必须遵守:返回值类型相同,方法名相同,形参列表相同。
-
访问权限不能更低,但是可以更高,private最低,public最高。
-
抛出异常不能更多,但是可以更少。
-
静态方法不存在重写。
-
覆盖只谈方法,不谈属性。
11、多态
**向上转型(upcasting):**子类型 --> 父类型,可以理解为自动类型转换。
**向下转型(downcasting):**父类型 --> 子类型,可以理解为强制类型转换。
在类和类之间,无论是向上转型还是向下转型,都必须具有继承关系,不然编译不通过。
**多态语法机制:**父类型的引用指向子类型对象这种机制导致程序在编译阶段和运行阶段出现了两种不同的形态或状态,这种机制可以称为一种多态语法机制。
**多态的作用:**降低程序的耦合度,提高程序的扩展力。能使用多态就多使用多态,即父类型引用指向子类型对象。
**多态的核心思想:**面向抽象编程,尽量不要面向具体编程。
**示例:**重点在注释哦
public class Animal{
public void run(){
System.out.println(“动物在移动!”);
}
}
public class Cat extends Animal{
public void run(){
System.out.println(“猫在散步!”);
}
public void catchMouse(){
System.out.println(“猫在抓老鼠!”);
}
}
public class Bird extends Animal{
public void run(){
System.out.println(“鸟儿在飞翔!”);
}
}
public class Test{
public static void main(String[] args){
// 此处为向上转型,从Cat类型自动转换为Animal类型
Animal cat1 = new Cat();
// 向上转型之后,可以访问父类型中的方法,但是如果这个方法被子类型中重写了
// 那么执行的就是子类型中的方法了,并且类型转化之后不能再执行子类型中特有的方法了
// 比如catchMouse方法,但是需要注意的是,虽然类型转换了,但是引用指向的堆内存中的
// 对象依然是最开始创建的Cat类型的源对象cat1,所以执行方法时原则就是子类型中没有就执行继承自父类型的方法,如果子类型中有这个方法时就执行子类型中的方法,但是不能执行子类型中特有的方法。
// 在编译阶段会将符合语法的该对象的方法绑定,这个过程称之为静态绑定,只有静态绑定成功之后才能运行程序。这个例子中,静态绑定是将Animal的move方法绑定到cat1对象,因为cat1是声明为Animal类型的,而Animal类是有move方法的,所以能绑定成功。
// 在运行阶段则会将实际运行的方法绑定到该对象上,这个过程称之为动态绑定,这个例子中,动态绑定是,在运行时,由于是先在内存中生成的对象是new出来的Cat类型的对象,虽然在等号赋值运算时类型被转换为Animal类型了,但是内存中其实还是那个被创建好的Cat类型的cat1对象,所以会执行Cat类中的move方法。
cat1.run(); // 输出为:猫在散步!
// 此处会编译不通过,虽然cat对象有catchMouse方法,但是类型转换后,因为Animal类型中没有catchMouse方法,所以编译不通过,即静态绑定失败。当然,也就不可能继续运行了。
cat1.catchMouse();
// 向下转型,这里不仅能编译通过,还能正确执行catchMouse方法,因为cat1其本质就是最初在内存中创建的Cat类型对象,而Cat类是由这个方法的
Cat cat2 = (Cat)cat1;
cat2.catchMouse();
// 此处的向下转型编译能能通过,但是运行会报错java.lang.ClassCastException(除了空指针异常之外另一个著名的异常),即类型转换异常,而且只有在向下转型的时候会发生。
// 因为第一个语句向上转型后,其实际还是个Bird类型对象,在第二个语句的向下转型,因为
// Animal类型和Cat类型之间具有继承关系,所以可以编译通过,但是运行时由于它本质是Bird类型
// 对象,不能转换成Cat类型对象,因为Bird和Cat之间没有继承关系,所以会报错。
Animal bird1 = new Bird();
Cat cat3 = (Cat)bird1;
}
}
12、instanceof运算符
语法:“引用 instanceof 数据类型名”,返回值为true/false,true表示这个引用指向的内存真实对象就是该数据类型的对象,false则表示这个引用指向的内存真实对象不是该数据类型的对象。如上例中“Animal bird1 = new Bird();”的bird1虽然转换成了Animal类型,但其真实内存对象其实是Bird类型的,所以如果执行“bird1 isinstanceof Bird”就会返回true。
Java编程规范中,在进行强制类型转换时,建议先使用instanceof运算符判断引用的类型再进行转换。
13、抽象类
抽象类使用abstract关键字修饰,是类和类之间共同特征的提取而形成的类,通常抽象类中含有抽象方法,但也不是说抽象类中就一定需要定义抽象方法。对于抽象方法的定义,需要注意,它同样需要abstract关键字修饰,同时不能有大括号,还需要以分号结尾。
抽象类也属于一种引用类型,使用抽象类来定义一个子类的对象,这种语法正是多态的应用,即向上转型,父类型的引用指向子类型的对象。
// 语法
[修饰符列表] abstract class 类名{
// 通常含有抽象方法,但也不是必须的
类体;
}
示例:
// 抽象类使用abstract关键字修饰
abstract class Animal{
// 抽象方法也使用abstract关键字修饰
// 并且抽象方法定义时不能有大括号
public abstract void run();
}
class Dog extends Animal{
// 如果子类继承自抽象类,但自身又不是抽象类
// 那么子类就必须重写/覆盖/实现抽象类中的所有抽象方法
public void run(){
System.out.println(“小狗在奔跑!!!”);
}
}
使用抽象类时,应注意以下几点:
-
抽象类无法实例化,无法创建对象,只能是用于子类来继承。所以也由此引出另一个点,final关键字和abstract关键字是不能联合使用的,因为final修饰的类是无法被继承的。
-
抽象类的子类也可以是抽象类。
-
抽象类是可以有构造方法的,但是这个构造方法是给子类用的,因为抽象类是无法实例化的。
-
抽象类中可以没有抽象方法,但是有抽象方法的类必须是抽象类。
-
如果子类继承自抽象类,且子类不是抽象类,那么子类就必须实现(其实就是方法重写/覆盖)抽象类中的所有抽象方法(如果有)。当然,如果子类也是抽象的,那么抽象方法的实现就不是必须的。抽象方法的实现注意两点:去掉abstract关键字,以及加上具体实现的方法体。
14、接口
接口在学习时候虽然可以将它当做是类来理解,但是注意,接口并不是类,定义使用的关键字是interface而不是class,但是编译之后也是一个class字节码文件。
同时,和抽象类一样,接口也是一种引用类型,使用接口的时候,可以使用多态,或者说接口的使用离不开多态,因为接口本身无法直接创建对象,一旦创建对象就必然是接口的“子类”,即向上转型,父类型的引用指向子类型的对象。
// 语法
[修饰符列表] interface 接口名{
常量或抽象方法;
}
示例:
public class HelloWorld{
public static void main(String[] args){
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了
《Java中高级核心知识全面解析》
小米商场项目实战,别再担心面试没有实战项目:
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
g-vEopI55S-1713748032231)]
[外链图片转存中…(img-NmweHMGA-1713748032232)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了
《Java中高级核心知识全面解析》
[外链图片转存中…(img-70cjZ7gX-1713748032232)]
小米商场项目实战,别再担心面试没有实战项目:
[外链图片转存中…(img-FQqEZiNa-1713748032232)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!