包括在Java api中找不到一个可以交换两个变量的方法。这与Java语言的特性有关。通过一个图就可以知道上面程序的运行结果了。
main函数中的x,y和swap函数中的x,y分别存放在不同的区域,在main中调用swap函数的时候,会将main中的x,y的值赋给swap中的x,y。当swap函数中对x,y交换时只是对swap帧中的x,y做交换,并不会改变main中的x,y。所以当函数返回时main中的x,y并不会改变
b、引用数据类型的按值传递
引用数据数据类型分为三种:①接口 ②类 ③数组

public static void main(String[] args) {
int []a={10,20};
System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=10,a[1]=20;
swap(a, 0, 1);
System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;
}
public static void swap(int []a,int i,int j){
nt temp=a[i];
a[i]=a[j];
a[j]=temp;
System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;
}
//输出
/*a[0]=10 a[1]=20
a[0]=20 a[1]=10
a[0]=20 a[1]=10
*/

运行程序后发现,swap函数对a[0] ,a[1]的操作竟然影响到了main函数中的a[0] ,a[1]的值,真是不可思议。为什么会产生如此之结果。原来引用类型的按值传递,传递的是对象的地址
由图可以看出在swap中仅仅是得到了数组的地址,并没有对数组的元素进行复制,在swap中对数组的操作是直接对main函数中数组的操作,因此swap函数返回后main函数中的a[0] ,a[1]的值发生交换
引用:https://blog.csdn.net/u013309870/article/details/75499175
9、对象的一对一关系
java中对象的对应关系有很多种,比如单向一对一,双向一对一,一对多,多对一,多对多等,其实现原理相同
其实可以理解为类的组合问题,把对象当做另一个的属性来操作,使得其产生对应关系(很多设计模式就是通过类的组合实现的)

分别是Hero、Weapon、One2One(包含主函数)
class Hero {
private String name; //属性私有化 ,防止外面直接赋值和调用
private int age;
private Weapon weapon; //声明一个武器类的对象 (私有化)
//此处省略get,set方法和构造器
}
class Weapon {
private String name;
private int age;
private Hero hero; //声明一个对象
//此处省略get,set方法和构造器
}
public class One2One {
public static void main(String[] args) {
Hero hero = new Hero("刘备",35); //实例化一个对象,并且赋值
Weapon weapon = new Weapon("双股剑",3);
//建立关系 ,(一句代码搞定)
hero.setWeapon(weapon); //把武器类对象设置成英雄类中的一个属性
weapon.setHero(hero);
//输出结果,用英雄类查找其武器
System.out.println("我的名字叫"+hero.getName()+",我现在"+hero.getAge()+"岁了,我用的武器是"+w.getName()+",等级为"+w.getAge()+"级。");
//我的名字叫刘备,我现在35岁了,我用的武器是双股剑,等级为3级。
hero.setAge(350); //修改其属性
weapon.setName("生锈的双股剑");
weapon.setAge(2);
//Hero h = weapon.getHero();
//用武器查找其主人
System.out.println("我是"+weapon.getName()+",我的等级已经降落为"+weapon.getAge()+"级了,我的主人是"+weapon.getHero().getName()+",现在已 经"+weapon.getHero().getAge()+"岁了");
//我是生锈的双股剑,我的等级已经降落为2级了,我的主人是刘备,现在已经350岁了
}

引用:https://blog.csdn.net/IT_arookie/article/details/83350946
10、static关键字
static关键字的作用:方便在没有创建对象的情况下来进行调用(方法/变量)。
a、使用static关键字修饰一个属性:声明为static的变量实质上就是全局变量
b、使用static关键字修饰一个方法:在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法(类调用)
c、使用static关键字修饰一个类(内部类):
声明为static的方法有以下几条限制:
它们仅能调用其他的static 方法,反过来是可以的。
它们只能访问static数据。
它们不能以任何方式引用this或super。
不允许用来修饰局部变量
可以参考:https://www.cnblogs.com/dolphin0520/p/3799052.html
11、main方法分析
主方法:
public static void main(String[] args){
//代码块
}
public:公有的,最大的访问权限
static:静态的,无需创建对象
void::表示没有返回值,无需向JVM返回结果
main:方法名,固定的方法名
String[] args:表示参数为字符串数组,可以在调用方法时传入参数
12、继承
继承是面向对象三大特征之一
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类
被继承的类称为父类(超类),继承父类的类称为子类(派生类)
通过继承可以实现代码重用
子类拥有父类非 private 的属性、方法。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
构造器而言,它只能够被调用,而不能被继承,可以通过使用super()进行调用,
对于继承而已,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要显示的指定父类的构造器(通过super()),而且必须是在子类构造器中做的第一件事(第一行代码)。
对于protected而言,它指明就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他却是可以访问的
Java 的继承是单继承,但是可以多重继承,
语法:[访问权限] class 子类名 extends 父类名{
类体定义;
}
示例:
public class Dog{
private String name;
private String sex;
public void eat(){System.out.println(“吃饭”);}
}
public class HomeDog extends Dog{
//类的定义
}
public class HuskyDog extends Dog{
//类的定义
}
protected(受保护的访问权限修饰符,用于修饰属性和方法,使用protected修饰的属性和方法可以被子类继承)
(1)继承是发生在多个类之间
(2)继承使用关键字extends
(3)JAVA只能单继承,允许多层继承
(4)被继承的类叫父类(超类),继承父类的类叫子类(派生类)
(5)在父类中的非私有属性和方法可以被子类继承
(6)protected(受保护的访问权限修饰符),修饰的属性或方法可以被子类继承
(7)构造方法不能被继承
(8)创建对象会调用构造方法,调用构造方法不一定就是创建对象
(9)实例化子类对象,会先调用父类的构造方法,如果父类中没有默认的构造方法,那么子类必须显示的通过super(...)来调用父类的带参构造方法,super也只能在子类构造方法中的第一句
继承的好处:
a、提高代码的复用性
b、提高代码的维护性
c、让类与类之间产生关系,是多态的前提
继承的缺点:增强了类与类之间的耦合性
13、对象初始化

public class CodeBlockTest {
public static void main(String[] args) {
Child child = new Child();
}
}
class Father {
public static String fatherStr1 = "fatherStr1(静态字段初始化值)";
public String fatherStr2 = "fatherStr2(字段初始化值)";
static {
System.out.println("父类静态代码块:" + fatherStr1);
fatherStr1 = "fatherStr1(静态代码块赋值)";
}
{
System.out.println("父类构造代码块:" + fatherStr2);
fatherStr2 = "fatherStr2(构造代码块赋值)";
}
public Father() {
System.out.println("父类构造函数块:" + fatherStr2);
fatherStr2 = "fatherStr2(构造函数赋值)";
}
}
class Child extends Father {
public static String childStr1 = "childStr1(静态字段初始化值)";
public String childStr2 = "childStr2(字段初始化值)";
static {
System.out.println("子类静态代码块:" + childStr1);
childStr1 = "childStr1(静态代码块赋值)";
}
{
System.out.println("子类构造代码块:" + childStr2);
childStr2 = "childStr2(构造代码块赋值)";
}
public Child() {
System.out.println("子类构造函数:" + childStr2);
childStr2 = "childStr2(构造函数赋值)";
}
}
// 输出结果:
// 父类静态代码块:fatherStr1(静态字段初始化值)
// 子类静态代码块:childStr1(静态字段初始化值)
// 父类构造代码块:fatherStr2(字段初始化值)
// 父类构造函数块:fatherStr2(构造代码块赋值)
// 子类构造代码块:childStr2(字段初始化值)
// 子类构造函数:childStr2(构造代码块赋值)

通过每执行一个代码块或构造函数,输出字段在上一代码块执行后的值,以此来探究对象的初始化顺序。
由目前的输出结果可知,对于对象的初始化顺序,我们可以得出以下结论:
1. 父类静态字段初始化
2. 父类静态代码块、子类静态字段初始化 (接下来探究两者的顺序)
3. 子类静态代码块
4. 父类普通字段初始化
5. 父类构造代码块
6. 父类构造函数
7. 子类普通字段初始化
8. 子类构造代码块
9. 子类构造函数

public class CodeBloacTest2 {
public static void main(String[] args) {
Child child = new Child();
}
}
class Father {
public static String fatherStr = "(静态字段初始化值)";
static {
System.out.println("父类静态代码块:fatherStr" + fatherStr);
fatherStr = "(静态代码块赋值)";
}
}
class Child extends Father {
public static String childStr = fatherStr;
static {
System.out.println("子类静态代码块:childStr = fatherStr" + childStr);
childStr = "(静态代码块赋值)";
}
}
// 输出结果:
// 父类静态代码块:fatherStr(静态字段初始化值)
// 子类静态代码块:childStr = fatherStr(静态代码块赋值

我们在子类静态字段childStr初始化的时候,赋的是父类静态字段fatherStr的值。由输出结果可知,childStr初始化后的值是父类静态代码块执行后赋予fatherStr的值。由此可知两者的执行顺序为:父类静态代码块==>子类静态字段初始化
初始化顺序(最终结果):
父类静态字段初始化
父类静态代码块
子类静态字段初始化
子类静态代码块
父类普通字段初始化
父类构造代码块
父类构造函数
子类普通字段初始化
子类构造代码块
子类构造函数
引用:https://www.jb51.net/article/111157.htm
14、方法的重写
方法重写(overriding method)
在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想做一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
在子类和父类中,重写方法后,在调用时,以创建的对象类型为准,会调用谁的方法。
重写特性:
a、发生在子父类中,方法重写的两个方法返回值、方法名、参数列表必须完全一致(子类重写父类的方法)
b、子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)
c、子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
d、父类中的方法若使用private、static、final任意修饰符修饰,那么,不能被子类重写。
面试题 :overloading与overriding的区别?
15、super关键字
可以理解为对父类的引用,使用super来调用父类的属性,方法,和构造方法
super可以完成以下的操作:
a、使用super调用父类中的属性,可以从父类实例处获得信息。
b、使用super调用父类中的方法,可以委托父类对象帮助完成某件事情。
c、使用super调用父类中的构造方法(super(实参)形式),必须在子类构造方法的第一条语句,调用父类中相应的构造方法,若不显示的写出来,默认调用父类的无参构造方法,比如:super();
16、final关键字
使用final关键字完成以下的操作:
a、使用final关键字声明一个常量
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的
b、使用final关键字声明一个方法
该方法为最终方法,且只能被子类继承,但是不能被子类重写。
c、使用final关键字声明一个类
该类就转变为最终类,没有子类的类,fianl修饰的类无法被继承。
d、在方法参数中使用final,在该方法内部不能修改参数的值(在内部类中详解)
当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化
引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的。
可以参考:https://www.cnblogs.com/xiaoxi/p/6392154.html
17、抽象类
抽象类的基本概念
(1)很多具有相同特征和行为的对象可以抽象为一个类;很多具有相同特征和行为的类可以抽象为一个抽象类。
(2)使用abstract关键字声明的类为抽象类
定义一个抽象类
abstract class Animal{
public abstract void move();
}
abstract class Person extends Animal{
private String name;
//...
public abstract void eat();//抽象方法
}
抽象类的规则:
a、抽象类可以没有抽象方法,有抽象方法的类必须是抽象类
b、非抽象类继承抽象类必须实现所有抽象方法
c、抽象类可以继承抽象类,可以不实现父类抽象方法。
d、抽象类可以有方法实现和属性
e、抽象类不能被实例化
f、抽象类不能声明为final
g、抽象类可以有构造方法
18、接口
接口的定义格式:
interface 接口名称{
全局常量 ;
抽象方法 ;
}
示列:
interface IEat{
//public abstract void eat();
void eat(); //默认为public abstract void eat();
//public static final int NUM = 10;
int NUM = 10; }
interface ISleep extends IEat{
void sleep();
}
接口的使用规则:
(1)定义一个接口,使用interface关键字
(2)在一个接口中,只能定义常量、抽象方法,JDK1.8后可以定义默认的实现方法
(3)接口可以继承多个接口:extends xxx,xxx
(4)一个具体类实现接口使用implements关键字
(5)一个类可以实现多个接口
(6)抽象类实现接口可以不实现接口的方法
(7)在接口中定义的方法没有声明 访问修饰符,默认为public
(8)接口不能有构造方法
(9)接口不能被实例化
java8新增
(1)增加了default方法和static方法,这两种方法完全可以有方法体
(2)default方法属于实例,static方法属于类(接口)
(3)接口中的静态方法不会被继承,接口中的静态变量会被继承
public interface IUser {
static void say() {
System.out.println("say_" + IUser.class);
}
default void eat() {
System.out.println("eat_" + IUser.class);
}
}
19、多态性