java----语言基础
重载:
//同一个类中,方法名相同,参数列表不同[java就是靠不同的参数列表来寻找方法的],返回值可以任意
public class Demo {
public static void main(String[] args) {
float num1 = 3;
float num2 = 4;
float x = add(num1,num2);
System.out.println(x);
}
public static int add(int a,int b){
return a+b;
}
public static float add(float a,float b){
return a*b;
}
}
可变参数:
sayhi(String... str){
}
此时的str可以传递,也可以不传递。但是可变参数必须放在最后面。它本身是一个数组
static:
static修饰字段
使用static关键字修饰一个字段:声明的static变量实际上就是一个全局变量
static修饰的方法不可以重写,所以接口和抽象方法中定义的static方法必须是需要方法体的。另外接口中定义的变量必须附初始值,抽象类定义的变量可以不需要附初始值。
使用static关键字修饰一个方法:可以直接使用类调用方法,和对象没有关系了
使用static关键字修饰一个类:内部类
如果需要了解跟多static关键字修饰字段,参考我的另一篇博客:https://www.cnblogs.com/yanxiaoge/p/10658660.html
public class Demo {
public static void main(String[] args){
System.out.print(Test.name);//一般定义静态字段,最好又类来调用;
//System.out.print(Test.name1); //只有定义了静态字段,类才可以直接调用
}
}
class Test{
String name1 = "dddsdfsd";
static String name = "dd";
}
static修饰方法
public class Demo {
public static void main(String[] args){
Test.setCountry("中国");
Test h = new Test();
System.out.print(h.country);
}
}
class Test{
static String country;
public static void setCountry(String country){ //静态方法只能访问静态字段;不能访问非静态字段
Test.country = country;
}
}
static代码块和构造代码块:
如果Test类继承了父类,会先执行父类的静态代码块和构造代码块(如果是创建对象的情况下)
static{}:代码块是类的加载过程中初始化阶段执行的。和new对象没有任何关系,比如Test.静态属性,也同样会触发static{},只是在new 对象过程中,如果发现当前类还没有被加载到内存,就会将类加载到内存,在初始化过程中执行了<clinit>() 方法,如果static{}中有打印信息,就会被打印出来,如果第二期new 对象的时候,发现类已经加载内存了,就不会再进行初始化了.也就是为什么多次new 对象,static 变量只有一个的原因了(全局共享),而且这个变量就和对象没有任何关系了(但是还是可以通过对象访问静态变量和静态方法的,一个对象对静态变量的修改会影响到另一个对象)
public class Demo {
public static void main(String[] args){
Test t = new Test();
Test t1 = new Test();
}
}
class Test{
static{
System.out.println("静态代码块");//在类中使用static定义,最先执行,只会创建一次(当创建第二个对象是,不会再执行该代码,static只存储一次)
}
{
System.out.println("构造代码块");//在类中定义,优先构造方法执行,每次创建对象都会执行
}
public Test(){
{
System.out.println("普通代码块"); //在方法中定义,方法被调用执行
}
System.out.println("我是构造方法");
}
}
通过类调用静态方法只会调用静态代码块,多次调用也会执行一次静态代码块。(如果继承父类,同样会先执行父类的)
public class Demo {
public static void main(String[] args){
Test.t();
Test.t();
}
}
class Test{
static{
System.out.println("静态代码块");//在类中使用static定义,最先执行,只会创建一次(当创建第二个对象是,不会再执行该代码,static只存储一次)
}
{
System.out.println("构造代码块");//在类中定义,优先构造方法执行,每次创建对象都会执行
}
public Test(){
{
System.out.println("普通代码块"); //在方法中定义,方法被调用执行
}
System.out.println("我是构造方法");
}
public static void t(){
}
}
Test t = null;不会有任何操作
调用通过类调用final修饰的字段(同时被static修饰,不然不能被类直接调用)不会初始化。
public class Demo {
//main方法会被调用,所有static会被执行
static {
System.out.println("x");
}
public static void main(String[] args){
//这样不会执行Test中的任意代码块
Test t = null;
}
}
class Test{
static{
System.out.println("静态代码块");//在类中使用static定义,最先执行,只会创建一次(当创建第二个对象是,不会再执行该代码,static只存储一次)
}
{
System.out.println("构造代码块");//在类中定义,优先构造方法执行,每次创建对象都会执行
}
public Test(){
{
System.out.println("普通代码块"); //在方法中定义,方法被调用执行
}
System.out.println("我是构造方法");
}
}
下面输出结果:构造。构造。静态。构造
public class B
{
public static B t1 = new B();
public static B t2 = new B();
{
System.out.println("构造块");
}
static
{
System.out.println("静态块");
}
public static void main(String[] args)
{
B t = new B();
}
}
final:
private static final int NUM = 10; //final表示该字段为常量,通常全部大写
final 修饰一个类,则该类不能被继承;final不可以修饰抽象类和接口
final 修饰一个方法不能重写,和static一样。
将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
接口中的变量都是final
常量类
public class Demo {
public static void main(String[] args){
Person person = new Person(11);
}
}
class Constant{ //将常量专门放在一个类中,让其他的类继承他[常量不一定必须初始化,可以在构造器中默认赋值(如果采用这种方法给常量赋值,常量不能用static修饰)]
public static final int NUM = 10; //加上static,目的不用创建了对象,就可以直接调用常量;
}
class Person extends Constant{
private final int NUM;
public Person(int id){
NUM = id; //在构造器中的初始化
}
{
System.out.println(Constant.NUM);
}
}
volatile:
背景
数据的计算(1+1),首先是从内存中加载代cpu缓存中,在加载到cpy计算。cpu计算完成返回的结果放到cpy缓存区,至于什么时候在返回到内存,是不确定的,看cpu空闲时间。有没有方法能让计算结果立刻返回到内存中。
volatile是Java提供的一种轻量级的同步机制,在并发编程中,它也扮演着比较重要的角色。同synchronized相比(synchronized通常称为重量级锁),volatile更轻量级,相比使用synchronized所带来的庞大开销,但是注意 volatile不能确保原子性,在访问volatile变量时,不会执行加锁操作,因此也就不会执行线程阻塞。所以volatile变量是一种比sychhronized关键字更轻量级的同步机制。
原子性:原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1;
volatile的适用场景:
1、对变量的写入操作不依赖其当前值(如 number++ 、count = count * 5等)
2、该变量没有包含在具有其它变量的不变式中
3、volatile关键字另一个作用就是禁止指令重排优化
参考:https://www.cnblogs.com/xuwenjin/p/9051179.html
https://www.cnblogs.com/chengxiao/p/6528109.html
补充可以看看CAS:https://blog.csdn.net/v123411739/article/details/79561458
面对对象:
对象被创建的步骤
1.分配对象空间,并将对象成员变量初始化为0或空
2.执行属性值的显式初始化
3.执行构造方法(此时的对象已经被创建,我们可以在这一步对对象进行进一步的初始化工作)
4.返回对象的地址给相关的变量
public class Demo {
public static void main(String[] args){
Horse h = null;
h = new Horse();
// h.name = "dd";
h.eat();
h = null; //释放对象
}
}
class Horse{
String name;
public void eat(){
System.out.println(name);
}
}
封装性:
public class Demo {
public static void main(String[] args){
Horse h1 = new Horse();
// h1.name = "小明";//由于 name设置了私有字段,此时在给对象赋值,会报错;
h1.setName("小明");
System.out.println(h1.getName());
}
}
class Horse{
//属性的封装
private String name;
private int age; //成员变量,在类中定义,在堆内存,对象清空,则成员变量清空,有默认初始值,像String引用变量初始值为null,int的初始值为0;
public void setName(String name){ //参数也是局部变量
int a = 111; //局部变量;在方法中定义,在栈内存,方法调用完毕,就清空,没有初始值,必须定义,赋值后,才能调用。
this.name = name;
}
public String getName(){
// return name;
return this.name; // 可以使用this调用其他方法和属性,this可以省略,this前面可以加上类名 Horse.this.name();
}
}
构造方法和构造方法的重载:
类似python中的__init__(self){}
public class Demo {
public static void main(String[] args){
Horse h = new Horse();
Horse h2 = new Horse(1);
}
}
class Horse{
public Horse(){ //方法名称和类名相同,没有返回值
System.out.println("我是构造方法");
}
public Horse(int a){
System.out.println("a="+a);
}
}
构造方法之间的调用,用this()
public class Demo {
public static void main(String[] args){
Horse h2 = new Horse(1);
}
}
class Horse{
public Horse(){ //默认构造方法,可以保留
}
public Horse(String b){ //方法名称和类名相同,没有返回值
System.out.println(b);
}
public Horse(int a){
this("11"); //调用另一个构造方法,注意,这条语句,只能放在最前面,否则报错;,限制了,不能调用多个;
this("22"); //报错,只能调用一个
System.out.println("a="+a);
}
}
对象之间的关联:
public class Demo {
public static void main(String[] args){
Hero hero1 = new Hero("刘备");
Weapon weapon1 = new Weapon("双股剑");
hero1.setWeapon(weapon1);//将对象传递给一个对象,实现对象之间的关联
System.out.println(hero1.getWeapon().getName());
}
}
class Hero{
//属性的封装
private String name;
private Weapon weapon;
public Hero(String name){
this.name = name;
}
public void setWeapon(Weapon weapon){
this.weapon = weapon;
}
public Weapon getWeapon(){
return this.weapon;
}
}
class Weapon{
private Hero hero;
private String name;
public Weapon(String name){
this.name = name;
}
public void setHero(Hero hero){
this.hero = hero;
}
public String getName(){
return this.name;
}
}
继承:
方法的重载:发生在同一个类中,函数名相同,参数列表不相同,与返回值返回值(类型)无关;
方法的重写:发生在继承的关系中,函数名相同,参数列表相同,返回值(类型)需要相同。子类的访问修饰符需要大于或者等于父类的访问修饰符,子类的异常声明要小于或等于父类的异常声明,如果方法被private 、static修饰,那么方法不能被继承/重写。 final修饰,只能继承,不能重写
public class Demo {
public static void main(String[] args){
Dog dog = new Dog(); //子类创建对象时 ,也会 自动 调用父类的默认的构造方法
System.out.println(dog.name);
dog.print();
}
}
class Animal{
protected String name = "动物";
public Animal(){
System.out.println("我是Animil 默认构造方法");
}
public Animal(String name){
System.out.print("我是Animial 传参构造方法");
}
public void print(){
System.out.println("Animal");
}
}
class Dog extends Animal{ //继承的写法
public Dog(){
super("传值"); //如果有super,就会继承super所指的构造方法,具体执行那一个,看传参的列表
// super(); //如果没有传值,就会执行父类的默认的构造方法,前提父类必须保留默认的构造方法;
//注意1:默认情况下,会自动添加super(),如果自己写了super,就会覆盖默认的
//注意2:super(),只能方法最开始的位置
}
public void print(){
super.print(); //继承父类的方法;
System.out.println("Dog");
}
}
抽象类:
1、抽象类可以没有抽象方法,有抽象方法的一定是抽象类
2、非抽象类继承抽象类必须实现所有的抽象方法
3、抽象类可以继承抽象类,可以不实现父类的抽象方法
4、抽象类可以有方法实现和属性
5、抽象类不能被实例化
6、抽象类不能声明final
7、抽象类可以有构造方法
public class Demo {
public static void main(String[] args){
Dog dog = new Dog();
}
}
abstract class Animal{ //声明该类是一个抽象类,只能继承,不能实例化
{
System.out.println("可以有构造方法");
}
public abstract void eat(); //可以没有抽象方法 ,如果有了抽象方法,该类必须是抽象类,并且该抽象方法必须子类实现;
public void run(){ //普通的方法可以不用被实现
System.out.print("我可以跑");
}
}
class Dog extends Animal{
public void eat(){
}
}
抽象类设置了很多属性,这些属性有什么意义?
当我们子类继承父类,子类实例化的时候就可以使用super(),像父类传值。父类就可以在特定的场景使用这些属性。
当然,有些属性是由父类自己设置的。
接口:
1、抽象类实现接口,可以不实现接口的方法,非抽象类,必须实现接口的所有的方法;
2、接口的方法没有声明访问修饰符,默认为public
3、接口不能有构造方法,接口不能被实例化
4、接口之间的继承用extends ,定义接口用interface ,类实现接口用implements
5、接口只能定义常量,抽象方法,(jdk1.8之后有默认的实现方法,和静态方法)
6、final不可以修饰接口
public class Demo {
public static void main(String[] args){
Person person = new Person();
person.print(); //默认的方法实现;
}
}
interface IEat{
// public abstract void eat();
void eat(); //简写,定义抽象方法
// public final static int NUM = 10;
int NUM = 10; //简写,定义常量
public default void print(){
System.out.println("默认方法实现"); //jdk1.8之后有 默认方法实现(加上default),不能有其他的方法实现
}
}
interface ISleep{
void sleep();
}
interface IRun extends IEat,ISleep{ //接口可以有多继承
void run();
}
class Person implements IRun,ISleep{ //接口的实现,类可以继承多个接口(不是接口的继承)
public void sleep(){} //必须实现接口的所有的方法
public void run(){}
public void eat(){}
}
多态:
public class Demo {
public static void main(String[] args){
Chick smailchick = new SmailChick(); //用父类的引用指向子类对象,(用大的类型接受小的类型,向上转型,自动转换)
eat(smailchick);
SmailChick smailchick2 = new SmailChick();
eat(smailchick2);
Chick bigchick = new BigChick();
eat(bigchick);
}
public static void eat(Chick c){ //多态性,Chick可以接受比他小的或者等于他的类型,(例如int可以接受short类型)
c.eat();
// c.song(); //直接写会报错,原因Chick中没有song方法,在运行的时候,c才是所new的对象,在编译的时候c还是chick
if(c instanceof BigChick){ //在转换之前做类型的判断
// BigChick bigchick = (BigChick)(c); //若果父类中没有定义song()方法,就需要 强制转换 将Chick转变成BigChick
// bigchick.song();
((BigChick)c).song(); //简写
}
}
}
abstract class Chick{
public abstract void eat();
}
class SmailChick extends Chick{
public SmailChick(){
super();
}//默认自动添加
public void eat(){
System.out.println("我是小鸡,我爱吃米");
}
}
class BigChick extends Chick{
public void eat(){
System.out.println("我是大鸡,我爱吃虫");
}
public void song(){
System.out.println("我是大鸡,我会唱歌");
}
}
this的本质
指明当前的对象,不能放到static静态方法中
class Test{
int a;
public Test(int a){
//给成员变量进行赋值
this.a = a;
}
public Test(){
//调用另一个构造方法,只能放在代码的第一行(所以只能有一个)
this(1);
}
}
java中的new到底为我们做了什么?
参考https://www.cnblogs.com/KingIceMou/p/7245446.html
补充
访问修饰符

内部类:
内部类的好处
可以使用外部类的元素
class Demo extends B{
private String a;
class Test{
public void test() {
System.out.println(a);
}
}
}
匿名内部类可以加private protected修饰,隐藏对象
public class Demo {
public static void main(String[] args){
A a = new A();
//实现隐藏
Instance in = a.getIn();
}
}
interface Instance{}
class A{
public B getIn(){
return new B();
}
private class B implements Instance{
}
}
可以实现多重继承
class A {
public String name() {
return "小明";
}
}
class B {
public int age() {
return 18;
}
}
class Test {
private class test1 extends A {
}
private class test2 extends B {
}
public String name() {
return new test1().name();
}
public int age() {
return new test2().age();
}
public static void main(String args[]) {
Test mi = new Test();
System.out.println("姓名:" + mi.name());
System.out.println("年龄:" + mi.age());
}
}
避免修改接口而实现同一个类中两种同名方法的调用
你的类要继承一个类,还要实现一个接口,可是你发觉你继承的类和接口里面有两个同名的方法怎么办?
未使用内部类的情况
interface A{
void test();
}
class B{
void test(){
System.out.println("B");
}
}
class Demo extends B implements A{
@Override
public void test() {
//这种方法就调用不到B类的方法了
}
}
使用内部类的情况
interface A{
void test();
}
class B{
void test(){
System.out.println("B");
}
}
class Demo extends B{
//使用内部类来实现接口
class Test implements A{
@Override
public void test() {
}
}
}
成员内部类:
public class Demo {
public static void main(String[] args){
A a = new A();
// A.B b = a.new B(); //创建内部类,通常不建议这样调用
// b.print();
a.Bprint(); //通过接口来创建内部类,并调用类的方法
}
}
class A{
//成员内部类
public void Bprint(){
B b = new B();
b.print();
}
//成员内部类,建议设置私有.内部调用
private class B{
public void print(){
System.out.println("测试");
}
}
}
方法内部类:
public class Demo {
public static void main(String[] args){
A a = new A();
a.Aprint();
}
}
class A{
//方法内部类
public void Aprint(){
int x = 1;
// x++; //由于内部类调用了局部变量x,所以x不能修改;
System.out.println(x);
class B{
public void print(){
System.out.println("测试"+x); //一旦方法内部类中调用了局部变量,该变量默认是final,不可以被修改;
}
}
B b = new B(); //方法内部类只能在该方法内实例化
b.print();
}
}
解释:为什么方法内部类中类调用局部变量,该变量必须修饰为final(在jdk1.8之后,可以不用加,解释器会默认加上)?
当上面的Aprint方法结束了。方法直接出栈,栈中里面的局部变量清空,但是对象(内部类),可能GC垃圾回收机制,还没有将对象回收掉。而对象有调用着局部变量,此时就会报错,所以必须将该局部变量修饰为final,放在堆的常量区,这个即使方法出栈了,局部变量也不会被清空,而修饰了finnal的局部变量,则不能在进行修改操作了。
注意:没有被类调用的变量不会默认为final,可以进行修改操作;
内部类中可以使用不加final的静态变量
静态内部类:
静态内部类不依赖对象,所以开发项目的时候优先考虑
使用静态内部类不用担心内存泄漏的问题;
public class Demo {
public static void main(String[] args){
A.B b = new A.B();
b.print();
}
}
class A{
//静态内部类 ,不能调用非静态的方法和属性;
static class B{
public void print(){
System.out.println("静态内部类");
}
}
}
匿名内部类:
继承式匿名内部类
接口式匿名内部类
参数式匿名内部类
注意事项:
1、不能有构造方法(没有名字),只能有一个实例
2、不能定义任何静态成员,静态方法(内部类依赖对象,对象和静态是没有关系的)
3、不能是private static protected public (没有类,没办法加修饰符)
4、一定是是在new后面,用其隐含实现一个接口或者继承一个类
5、匿名内部类是局部的,所以局部内部类的所有的限制都对其生效
public class Demo {
public static void main(String[] args){
print1();
print2();
print3(new C(){
public void print(){
System.out.println("参数式内部类");
}
});
}
public static void print1(){
A a = new A(){
public void print(){
System.out.println("继承式内部类");
}
};//注意一定要有分号;
a.print();
}
public static void print2(){
B b = new B(){
public void print(){
System.out.println("接口式内部类");
};
};
b.print();
}
public static void print3(C c){
c.print();
}
}
abstract class A{
public abstract void print();
}
interface B{
void print();
}
abstract class C{ //interface class C{} 一样
public abstract void print();
}
总结:
每个内部类能独立的继承或一个(接口)的实现,所以无论外部类是否是否已经继承了某个(接口的)实现,对于内部类没有影响。
并且内部类为多继承的实现,提供了解决方案;
public class Demo {
public static void main(String[] args){
C c = new C();
c.print();
}
}
abstract class A{
}
abstract class B{
public abstract void print();
}
class C extends A{
class D extends B{
public void print(){
System.out.print("测试");
}
}
public void print(){
D d = new D();
d.print();
}
}
内部类访问外部内对象属性
class A{
private User user;
class B{
//如果需要访问user
User u = A.this.user;
}
}
父子类之间转换:
Father f1 = new Father(); Father f2 = new Son(); Son s1 = new Son(); //子类强转父类,不会有任何问题,只是不能在调用子类的方法,如果想调用子类的方法,之间在转换成子类就行,因为这个对象本身就是子类,本质没有改变,所以我们看方法都是用父类接受对象,在方法中在对对象进行转换成子类(判断是不是属于子类) (Father)s1 (Son)(Father)s1 //f2本身就是子类,f1本身就是父类 (Son)f1 报错 (Son)f2 不报错

浙公网安备 33010602011771号