黑马程序员——JAVA基础总结

时间:2023-01-14 00:30:16

------- android培训java培训、期待与您交流! ----------

一.逻辑运算符

:and(与) 

&运算的两边只有有一个是false,结果肯定是false。

只有两边都为true,结果才是true。

&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作

 

:or(或)

运算的两边只要有一个是true,结果肯定是true。

只有两边都为false。结果是false。

 

:xor(异或)

^符号的两边结果如果相同,结果是false。

两边的结果不同,结果是true。

通过异或运算能实现变量的交换

异或运算能够使数据中的某些位翻转,其他位不变。

这就意味着任意一个数与任意一个给定的值连续异或两次,值不变,可以用来加密。

即:a^b^b=a。将a=a^b代入b=a^b则得b=a^b^b=a;同理可以得到a=b^a^a=b;轻松完成交换。

 

:not(非)

非运算,判断事物的另一面。

!true = false

!false = true;

 

&& 

当左边为false时,右边不运算

&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式

 

|| 

当左边为true时,右边不运算

 

二.“==”和equals方法的区别

对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比较方法不同。
“==”比较两个变量本身的值,即两个对象在内存中的首地址。
“equals()”比较字符串中所包含的内容是否相同。

==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。

 

如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存。

例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。

equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。

例如:

String a=new String("hello");
String b=new String("hello");





两条new语句创建了两个对象,然后用a,b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。

如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:

boolean equals(Object o){
return this==o;
}





这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。

 

三.JAVA内存结构

Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,

有对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

1. Heap(堆):实例分配的地方,通过-Xms与-Xmx来设置

2. MethodArea(方法区域):类的信息及静态变量。对应是PermanetGeneration,通过-XX:PermSize来设置

3. JavaStack(java的栈):虚拟机只会直接对Javastack执行两种操作:以帧为单位的压栈或出栈。通过-Xss来设置,若不够会抛出*Error

4. ProgramCounter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。

5. Nativemethodstack(本地方法栈):保存native方法进入区域的地址

当中Heap和MethodArea是被所有线程的共享使用的;

而Javastack,Programcounter和Nativemethodstack是以线程为粒度的,每个线程独自拥有自己的部分

 

四.static关键字与静态代码块

1.stasic(静态)关键字

用于修饰成员(成员变量和成员函数) PS:不能修饰局部

 

被修饰后的成员具备以下特点:

1、随着类的加载而加载 也就是说:静态会随着类的消失而消失,说明它的生命周期最长

2、优先于对象存在

明确一点:静态时先存在,对象是后存在的

3、被所有对象所共享

4、可以直接被类名调用,写法格式 类名.静态成员

 

实例变量和类变量的区别:

1、存放位置

类变量随着类的加载而存在于方法区中

实例变量随着对象的建立而存在于堆内存中

2、生命周期

类变量生命周期最长,随着类的消失而消失

实例变量生命周期随着对象的消失而消失

 

使用注意:

1、静态方法只能访问静态成员,因为静态会先存在,而那时没有对象,调用没有的成员变量就会产生错误

非静态方法既可以访问静态也可以访问非静态

class Person
{
String name;
static Stringcountry= "cn";
public staticvoidshow() //静态方法
{
System.out.println("..."+name);//调用了非静态的name
}
}
class StaticDemo
{
public staticvoidmain(String[]args)
{
Person.show();//静态可以用类名调用,此处报错,因为静态方法show调用了非静态的name(因为静态会先存在,而那时没有对象,此时name没有对象,所以无法调用)
}
}



 

2、静态方法中不可以写this,super关键字

因为静态优先于对象存在,(没有对象就无法调用)所以静态方法中不可以出现this

 

3、主函数是静态的

主函数:是一个特殊的函数,作为程序的入口,可以被jvm调用

public:代表着该函数访问权限是最大的

static:代表主函数随着类的加载就已经存在了

void:主函数没有具体的返回值。

main:函数名,不是关键字,只是一个jvm识别的固定的名字。

String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。

主函数是固定格式的

 

PS:假如在主函数中要调用非静态方法,可以new一个对象

class StaticDemo
{
int num =4;
public staticvoidmain(String[] args)
{
newStaticDemo().show(); //new一个对象来调用show方法
}

publicvoidshow() //非静态方法
{
System.out.println(num);
}
}




 

静态有利有弊

利处:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份,可以直接被类名调用

弊端:生命周期过长

访问出现局限性(静态虽好,只能访问静态)

 

什么时候定义静态变量(类变量)?

当对象中出现共享数据时,该数据被静态所修饰

对象中的特有数据要定义成非静态存在于堆内存中

 

什么时候定义静态函数?

当功能内部没有访问到非静态数据(对象的特有数据)

那么该功能可以定义成静态的

 

 

2.静态代码块

格式:

static
{
静态代码块中的执行语句
}





特点:随着类的加载而执行,只执行一次,并优先于主函数

用于给类进行初始化

例:

class StaticCode
{
static
{
System.out.println("a");
}
}
class StaticCodeDemo
{
static
{
System.out.println("b");
}
public staticvoidmain(String[] args)
{
newStaticCode();
newStaticCode();
System.out.println("over");
}
static
{
System.out.println("c");
}
}





结果

b
c
a
over


     

只有1个a是因为a那个类已经在内存中了,不会再加载了

 

五.super和this的用法

this代表本类对象的引用

super代表父类的内存空间的标识。

当子父类出现同名成员时,可以用super进行区分

子类要调用父类构造函数时,可以使用super语句。

 

六.Overload和Override的区别

override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。

在覆盖要注意以下的几点:

1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;

2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;

3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;

4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

5、覆盖时,子类方法权限一定要大于等于父类方法权限

6、静态只能覆盖静态。

 

overload可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:

1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));

2、不能通过访问权限、返回类型、抛出的异常进行重载;

3、方法的异常类型和数目不会对重载造成影响;

4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。

 

七.final关键字

final可以修饰类,方法,变量。

final修饰的类不可以被继承。

final修饰的方法不可以被覆盖。

final修饰的变量是一个常量。只能被赋值一次。

内部类只能访问被final修饰的局部变量。

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

 

八.构造函数

1、 特点:

        a) 函数名与类名相同。

        b) 不用定义返回值类型。

        c) 不可以写return语句。

2、 作用:

        给对象进行初始化。

3、构造函数的小细节:

        当一个类中没有定义构造函数时,那么系统就会默认给该类加入一个空参数的构造函数。当在类中自定义了构造函数后,默认的构造函数就没有了。

4、构造函数和一般函数在写法上有不同。

在运行上也有不同:

        构造函数式在对象一建立就运行,给对象初始化。而一般方法是对象调用才执行,给是对象添加对象具备的功能。一个对象建立,构造函数只运行一次。而一般方法可以被该对象调用多次。

5、什么时候定义构造函数?

        当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。

6、构造代码块

       作用:给对象进行初始化。对象一建立就运行,而且优先于构造函数运行。

和构造函数的区别:

       构造代码块是给所以对象进行初始化。

       而构造函数是给对应的对象初始化。

构造代码块中定义的是不同对象共性的初始化内容。