- Links, Symbolic or Otherwise
- Creating a Symbolic Link
- Creating a Hard Link
- Detecting a Symbolic Link
- Finding the Target of a Link
- Внутренние и вложенные классы java. Часть 2
- Передача параметров в Java: по значению или по ссылке?
- Пример № 2
- Передача параметров в Java: по значению или по ссылке?: 2 комментария
- Добавить комментарий Отменить ответ
Links, Symbolic or Otherwise
As mentioned previously, the java.nio.file package, and the Path class in particular, is «link aware.» Every Path method either detects what to do when a symbolic link is encountered, or it provides an option enabling you to configure the behavior when a symbolic link is encountered.
The discussion so far has been about symbolic or soft links, but some file systems also support hard links. Hard links are more restrictive than symbolic links, as follows:
- The target of the link must exist.
- Hard links are generally not allowed on directories.
- Hard links are not allowed to cross partitions or volumes. Therefore, they cannot exist across file systems.
- A hard link looks, and behaves, like a regular file, so they can be hard to find.
- A hard link is, for all intents and purposes, the same entity as the original file. They have the same file permissions, time stamps, and so on. All attributes are identical.
Because of these restrictions, hard links are not used as often as symbolic links, but the Path methods work seamlessly with hard links.
Several methods deal specifically with links and are covered in the following sections:
Creating a Symbolic Link
If your file system supports it, you can create a symbolic link by using the createSymbolicLink(Path, Path, FileAttribute) method. The second Path argument represents the target file or directory and might or might not exist. The following code snippet creates a symbolic link with default permissions:
Path newLink = . ; Path target = . ; try < Files.createSymbolicLink(newLink, target); >catch (IOException x) < System.err.println(x); >catch (UnsupportedOperationException x) < // Some file systems do not support symbolic links. System.err.println(x); >
The FileAttributes vararg enables you to specify initial file attributes that are set atomically when the link is created. However, this argument is intended for future use and is not currently implemented.
Creating a Hard Link
You can create a hard (or regular) link to an existing file by using the createLink(Path, Path) method. The second Path argument locates the existing file, and it must exist or a NoSuchFileException is thrown. The following code snippet shows how to create a link:
Path newLink = . ; Path existingFile = . ; try < Files.createLink(newLink, existingFile); >catch (IOException x) < System.err.println(x); >catch (UnsupportedOperationException x) < // Some file systems do not // support adding an existing // file to a directory. System.err.println(x); >
Detecting a Symbolic Link
To determine whether a Path instance is a symbolic link, you can use the isSymbolicLink(Path) method. The following code snippet shows how:
Path file = . ; boolean isSymbolicLink = Files.isSymbolicLink(file);
Finding the Target of a Link
You can obtain the target of a symbolic link by using the readSymbolicLink(Path) method, as follows:
Path link = . ; try < System.out.format("Target of link" + " '%s' is '%s'%n", link, Files.readSymbolicLink(link)); >catch (IOException x)
If the Path is not a symbolic link, this method throws a NotLinkException .
Внутренние и вложенные классы java. Часть 2
Внутренний класс связан с экземпляром его обрамляющего класса (из документации).
Пример внутреннего класса есть в документации.
/* Пример №7 */ class OuterClass < . class InnerClass < . >>
Так в чем же отличие, спросите вы. Объявления классов и вложенных и внутренних
одинаковые в данных случаях. Отличие в том, что внутренний класс связан с внешним классом через экземпляр, или через объект класса.
Чтобы создать экземпляр внутреннего класса, нам нужно сначала создать экземпляр внешнего класса. Затем создать внутренний объект, в пределах внешнего объекта, таким образом:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
/* Пример №8 файл Outer.java*/ package inner; /** * * @author Ar20L80 */ public class Outer < class InnerClass < >Outer()<> public static void main(String[] args) < Outer outerObject = new Outer(); Outer.InnerClass innerObject = outerObject.new InnerClass(); // создание экземпляра внутреннего класса >>
По-другому мы можем написать так:
/* Учебный пример №9 файл Outer5.java Внутренние классы Получить ссылку на внешний класс в конструкторе внутреннего */ package inner; /** * * @author Ar20L80 */ public class Outer5 < class Inner5< private Outer5 myOuter; Inner5()< myOuter = Outer5.this; >> public static void main(String[] args) < Outer5 outer5 = new Outer5(); >>
Обратите внимание на запись вида myOuter = Outer5.this; . Она означает получение ссылки на текущий экземпляр внешнего класса Outer5.this.
Рассмотрим свойства внутренних классов.
Внутренние классы есть смысл использовать, если они будут использовать элементы родителя,
чтобы не передавать лишнего в конструкторах. Внутренний класс неявно наследуется от внешнего класса, хотя мы не используем ключевое слово extends в случае с классом или implements в случае с интерфейсом. То есть, во внутреннем классе мы можем использовать весь унаследованный функционал внешнего класса. Может показаться, что это сомнительно. Но это дает нам более гибкий подход. Таким образом мы можем использовать во внутреннем классе, функционал унаследованный от внешнего класса.
Внутренний класс стоит использовать, когда нам нужна инкапсуляция. Во внутреннем классе мы, таким образом закрываем всё от «внешнего мира».
Например, Map.Entry — нигде кроме интерфейса Map и его реализаций он не используется. Смотрите исходный код Map.Entry и Map. Это я привел только один пример.
Далее рассмотрим пример явного наследования.
/* Учебный пример №10(1). файл Outer6.java Внутренние классы */ package inner; /** * * @author Ar20L80 */ class AnyClass<> // класс от которого наследуем Inner6 public class Outer6 < // внешний класс class Inner6 extends AnyClass< // внутренний класс явно унаследован от "прилегающего" // тут мы унаследовали внутренний класс от AnyClass<>// и можем расширить функциональность класса AnyClass<> // и класса Outer6 > >
В этом примере у нас, по сути, получилось множественное наследование, и мы можем использовать функционал класса AnyClass и функционал класса Outer6.
рис. 1
Здесь модификатор доступа у класса Outer6 по умолчанию. То есть класс Outer6 виден только в нашем пакете (package inner). Класс Inner6 закрыт от внешнего мира и внешнего воздействия.
То есть более «защищен».
Это только пример множественного наследования от «прилегающего» класса и класса «оболочки». На практике вам вряд-ли такое понадобится. Тут я рассматриваю такую возможность только в учебных целях и для лучшего понимания.
Замечание Выражение: «прилегающего» класса — взято из книги «Философия Java».
/* Учебный пример №11 файл Outer7.java Внутренние классы */ package inner; /** * * @author Ar20L80 */ class AnyClass2 < void anyClass2Method()<>> public class Outer7 < private int iOuterVar; private class Inner7 extends AnyClass2 < private Outer7 out7; public Inner7() < out7 = Outer7.this; // ссылка на окружающий класс >private int anyMethodOfInner7() < super.anyClass2Method();// можем вызвать метод нашего супер класса AnyClass2 return out7.iOuterVar; // можем обратиться к переменным // и методам Outer7 >> >
В этом примере видно, что мы можем использовать как поля и методы «окружающего» класса — Outer7, так поля и методы того класса, от которого мы наследовали внутренний класс — AnyClass2. Это дает нам несколько большие возможности и гибкость при использовании внутреннего класса. Хотя для множественного наследования более подходят интерфейсы.
Совет из книги «Философия Java. Брюс Эккель. ISBN 5-272-00250-4» c. 313:
«Каждый внутренний класс может независимо наследовать определенную реализацию.
Внутренний класс не ограничен при наследовании в ситуациях, где внешний класс уже наследует реализацию.»
Чтобы использовать внутренний класс, за пределами обычных методов «окружающего» класса необходимо создать объект внутреннего класса следующим способом.
ИмяВнешнегоКласса.ИмяВнутреннегоКласса.
Объект внутреннего класса сохраняет информацию о месте, где он был создан.
Майкл Морган. «Java 2.Руководство разработчика» ISBN 5-8459-0046-8
Брюс Эккель. «Философия Java.» ISBN 5-272-00250-4
Герберт Шилдт «Java. Полное руководство. 8-е издание.» ISBN: 978-5-8459-1759-1
Передача параметров в Java: по значению или по ссылке?
Для начала простой пример. Пусть у нас есть метод m(), который меняет имя кошки на Vasya:
Создадим кошку Petya, запомним ее в переменную oldCat и прогоним через метод:
Cat cat = new Cat("Petya"); Cat oldCat=cat; this.pass.m(cat); assertEquals("Vasya", cat.getName()); assertEquals(oldCat, cat);
Убедились, что теперь кошка стала Васей, при этом значение ссылки cat осталось прежним (впрочем, мы и не пытались его поменять внутри метода). Но имя то поменялось, то есть действия в методе мы проделали со внешней кошкой (созданной снаружи метода), а не с копией объекта кошки внутри метода. И это правда.
Но это не значит, что передача параметра произошла по ссылке. Она произошла по значению. И этим значением является ссылка.
То есть, oldCat и cat как до вызова метода располагалась по адресу 10 (к примеру), так и после вызова будут располагаться по адресу 10. Даже если бы внутри метода этот адрес попробовали поменять. А давайте «попробуем».
На следующем примере поясню, что такое настоящая передача по ссылке, и как это происходило бы к примеру в в языке C++ (в котором передача параметров и вправду может происходить по ссылке).
Пример № 2
Теперь у нас метод m1(), в котором мы переменной cat присвоим новую кошку Fifa:
Повторим вышеприведенный тест, и результат будет таким же. Внешняя кошка снова Vasya, и ссылка осталась прежней:
Cat cat = new Cat("Petya"); Cat oldCat=cat; this.pass.m1(cat); assertEquals("Vasya", cat.getName()); assertEquals(oldCat, cat);
Рассмотрим по шагам, что происходит.
- На строке (1) мы поменяли имя внешней кошки (поскольку cat здесь — все еще ссылка на внешнюю кошку) на имя Vasya, как и в первом примере.
- Но на строке (2) cat становится уже ссылкой на новую кошку, и ее адрес уже не 10, а какой-нибудь 42. Но этот адрес относится к внутренней ссылке cat, а никак не ко внешней. Внешняя ссылка cat не поменялась.
- То есть на строке (2) и далее все, что мы делаем с кошкой уже касается новой кошки Fifi, расположенной по новому адресу. Внешнюю кошку это уже не касается, имя меняется не у нее. Она остается по старому адресу, который хранится во внешних переменных cat и oldCat.
Вот в C++ мы могли бы передать ссылку — так, что на строке (2) не внутренняя cat встала на новый адрес, а адрес внешней cat встал бы на новую кошку. Вот в чем разница.
У нас же после прогона метода m1() ссылка cat по прежнему равна oldCat, значение ее не поменялось. В Java такого синтаксиса, как в С++ для передачи по ссылке нет.
Передача параметров в Java: по значению или по ссылке?: 2 комментария
Уже который раз натыкаюсь на это утверждение. «в Java все передается по значению!»
Почему такая путаница? Зачем людям вообще сранивать с С++?
Ссылка в с++ может хранить адрес объекта в куче. Можно передать объект по ссылке в качестве параметра в метод и это будет аналогично тому что происходит в Java — две ссылки на один и тот же объект. Просто разница лишь в том как вы это называете, а работа будет аналогичная!
В Java просто нету возможности создать объект на стэке или разыменовать указатель чтобы получить копию, зачем это придумали вообще?) Людей путать)
чуть проще. схематично
Obj obj1 = new Obj(«Вася»); m(obj1); // передается значение ссылки, т.е. адрес на объект assertEquals(«Вася», obj1.name); // оригинал ссылки obj1, объект не изменился void m(Obj obj2) < // копия ссылки obj1
obj2 = new Obj(«Петя»); // переписали копию ссылки, но не объект по ней
>
Добавить комментарий Отменить ответ
Прошу прощения: на комментарии временно не отвечаю.